GNU Unifont 17.0.05 Pan-Unicode font with complete Unicode Plane 0 coverage and partial coverage of higher planes

unihex2bmp.c
Go to the documentation of this file.
1/**
2 @file unihex2bmp.c
3
4 @brief unihex2bmp - Turn a GNU Unifont hex glyph page of 256 code points
5 into a bitmap for editing
6
7 @author Paul Hardy, unifoundry <at> unifoundry.com, December 2007
8
9 @copyright Copyright (C) 2007, 2008, 2013, 2017 Paul Hardy
10
11 This program reads in a GNU Unifont .hex file, extracts a range of
12 256 code points, and converts it a Microsoft Bitmap (.bmp) or Wireless
13 Bitmap file.
14
15 Synopsis: unihex2bmp [-iin_file.hex] [-oout_file.bmp]
16 [-f] [-phex_page_num] [-w]
17*/
18/*
19 LICENSE:
20
21 This program is free software: you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation, either version 2 of the License, or
24 (at your option) any later version.
25
26 This program is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with this program. If not, see <http://www.gnu.org/licenses/>.
33*/
34
35/*
36 20 June 2017 [Paul Hardy]:
37 - Adds capability to output triple-width and quadruple-width (31 pixels
38 wide, not 32) glyphs. The 32nd column in a glyph cell is occupied by
39 the vertical cell border, so a quadruple-width glyph can only occupy
40 the first 31 columns; the 32nd column is ignored.
41
42 21 October 2023 [Paul Hardy]:
43 - Added full prototypes in main function for init and hex2bit functions.
44*/
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49
50#define MAXBUF 256
51
52
53/**
54 @brief GNU Unifont bitmaps for hexadecimal digits.
55
56 These are the GNU Unifont hex strings for '0'-'9' and 'A'-'F',
57 for encoding as bit strings in row and column headers.
58
59 Looking at the final bitmap as a grid of 32*32 bit tiles, the
60 first row contains a hexadecimal character string of the first
61 3 hex digits in a 4 digit Unicode character name; the top column
62 contains a hex character string of the 4th (low-order) hex digit
63 of the Unicode character.
64*/
65 char *hex[18]= {
66 "0030:00000000182442424242424224180000", /* Hex digit 0 */
67 "0031:000000000818280808080808083E0000", /* Hex digit 1 */
68 "0032:000000003C4242020C102040407E0000", /* Hex digit 2 */
69 "0033:000000003C4242021C020242423C0000", /* Hex digit 3 */
70 "0034:00000000040C142444447E0404040000", /* Hex digit 4 */
71 "0035:000000007E4040407C020202423C0000", /* Hex digit 5 */
72 "0036:000000001C2040407C424242423C0000", /* Hex digit 6 */
73 "0037:000000007E0202040404080808080000", /* Hex digit 7 */
74 "0038:000000003C4242423C424242423C0000", /* Hex digit 8 */
75 "0039:000000003C4242423E02020204380000", /* Hex digit 9 */
76 "0041:0000000018242442427E424242420000", /* Hex digit A */
77 "0042:000000007C4242427C424242427C0000", /* Hex digit B */
78 "0043:000000003C42424040404042423C0000", /* Hex digit C */
79 "0044:00000000784442424242424244780000", /* Hex digit D */
80 "0045:000000007E4040407C404040407E0000", /* Hex digit E */
81 "0046:000000007E4040407C40404040400000", /* Hex digit F */
82 "0055:000000004242424242424242423C0000", /* Unicode 'U' */
83 "002B:0000000000000808087F080808000000" /* Unicode '+' */
84 };
85 unsigned char hexbits[18][32]; ///< The digits converted into bitmaps.
86
87 unsigned unipage=0; ///< Unicode page number, 0x00..0xff.
88 int flip=1; ///< Transpose entire matrix as in Unicode book.
89
90
91/**
92 @brief The main function.
93
94 @param[in] argc The count of command line arguments.
95 @param[in] argv Pointer to array of command line arguments.
96 @return This program exits with status 0.
97*/
98 int
99 main (int argc, char *argv[])
100{
101
102 int i, j; /* loop variables */
103 unsigned k0; /* temp Unicode char variable */
104 unsigned swap; /* temp variable for swapping values */
105 char inbuf[256]; /* input buffer */
106 unsigned filesize; /* size of file in bytes */
107 unsigned bitmapsize; /* size of bitmap image in bytes */
108 unsigned thischar; /* the current character */
109 unsigned char thischarbyte; /* unsigned char lowest byte of Unicode char */
110 int thischarrow; /* row 0..15 where this character belongs */
111 int thiscol; /* column 0..15 where this character belongs */
112 int toppixelrow; /* pixel row, 0..16*32-1 */
113 unsigned lastpage=0; /* the last Unicode page read in font file */
114 int wbmp=0; /* set to 1 if writing .wbmp format file */
115
116 unsigned char bitmap[17*32][18*4]; /* final bitmap */
117 unsigned char charbits[32][4]; /* bitmap for one character, 4 bytes/row */
118
119 char *infile="", *outfile=""; /* names of input and output files */
120 FILE *infp, *outfp; /* file pointers of input and output files */
121
122 /* initializes bitmap row/col labeling, &c. */
123 int init (unsigned char bitmap[17*32][18*4]);
124
125 /* convert hex string --> bitmap */
126 int hex2bit (char *instring, unsigned char character[32][4]);
127
128 bitmapsize = 17*32*18*4; /* 17 rows by 18 cols, each 4 bytes */
129
130 if (argc > 1) {
131 for (i = 1; i < argc; i++) {
132 if (argv[i][0] == '-') { /* this is an option argument */
133 switch (argv[i][1]) {
134 case 'f': /* flip (transpose) glyphs in bitmap as in standard */
135 flip = !flip;
136 break;
137 case 'i': /* name of input file */
138 infile = &argv[i][2];
139 break;
140 case 'o': /* name of output file */
141 outfile = &argv[i][2];
142 break;
143 case 'p': /* specify a Unicode page other than default of 0 */
144 sscanf (&argv[i][2], "%x", &unipage); /* Get Unicode page */
145 break;
146 case 'w': /* write a .wbmp file instead of a .bmp file */
147 wbmp = 1;
148 break;
149 default: /* if unrecognized option, print list and exit */
150 fprintf (stderr, "\nSyntax:\n\n");
151 fprintf (stderr, " %s -p<Unicode_Page> ", argv[0]);
152 fprintf (stderr, "-i<Input_File> -o<Output_File> -w\n\n");
153 fprintf (stderr, " -w specifies .wbmp output instead of ");
154 fprintf (stderr, "default Windows .bmp output.\n\n");
155 fprintf (stderr, " -p is followed by 1 to 6 ");
156 fprintf (stderr, "Unicode page hex digits ");
157 fprintf (stderr, "(default is Page 0).\n\n");
158 fprintf (stderr, "\nExample:\n\n");
159 fprintf (stderr, " %s -p83 -iunifont.hex -ou83.bmp\n\n\n",
160 argv[0]);
161 exit (1);
162 }
163 }
164 }
165 }
166 /*
167 Make sure we can open any I/O files that were specified before
168 doing anything else.
169 */
170 if (strlen (infile) > 0) {
171 if ((infp = fopen (infile, "r")) == NULL) {
172 fprintf (stderr, "Error: can't open %s for input.\n", infile);
173 exit (1);
174 }
175 }
176 else {
177 infp = stdin;
178 }
179 if (strlen (outfile) > 0) {
180 if ((outfp = fopen (outfile, "w")) == NULL) {
181 fprintf (stderr, "Error: can't open %s for output.\n", outfile);
182 exit (1);
183 }
184 }
185 else {
186 outfp = stdout;
187 }
188
189 (void)init(bitmap); /* initialize bitmap with row/column headers, etc. */
190
191 /*
192 Read in the characters in the page
193 */
194 while (lastpage <= unipage && fgets (inbuf, MAXBUF-1, infp) != NULL) {
195 sscanf (inbuf, "%x", &thischar);
196 lastpage = thischar >> 8; /* keep Unicode page to see if we can stop */
197 if (lastpage == unipage) {
198 thischarbyte = (unsigned char)(thischar & 0xff);
199 for (k0=0; inbuf[k0] != ':'; k0++);
200 k0++;
201 hex2bit (&inbuf[k0], charbits); /* convert hex string to 32*4 bitmap */
202
203 /*
204 Now write character bitmap upside-down in page array, to match
205 .bmp file order. In the .wbmp` and .bmp files, white is a '1'
206 bit and black is a '0' bit, so complement charbits[][].
207 */
208
209 thiscol = (thischarbyte & 0xf) + 2; /* column number will be 1..16 */
210 thischarrow = thischarbyte >> 4; /* charcter row number, 0..15 */
211 if (flip) { /* swap row and column placement */
212 swap = thiscol;
213 thiscol = thischarrow;
214 thischarrow = swap;
215 thiscol += 2; /* column index starts at 1 */
216 thischarrow -= 2; /* row index starts at 0 */
217 }
218 toppixelrow = 32 * (thischarrow + 1) - 1; /* from bottom to top */
219
220 /*
221 Copy the center of charbits[][] because hex characters only
222 occupy rows 8 to 23 and column byte 2 (and for 16 bit wide
223 characters, byte 3). The charbits[][] array was given 32 rows
224 and 4 column bytes for completeness in the beginning.
225 */
226 for (i=8; i<24; i++) {
227 bitmap[toppixelrow + i][(thiscol << 2) | 0] =
228 ~charbits[i][0] & 0xff;
229 bitmap[toppixelrow + i][(thiscol << 2) | 1] =
230 ~charbits[i][1] & 0xff;
231 bitmap[toppixelrow + i][(thiscol << 2) | 2] =
232 ~charbits[i][2] & 0xff;
233 /* Only use first 31 bits; leave vertical rule in 32nd column */
234 bitmap[toppixelrow + i][(thiscol << 2) | 3] =
235 ~charbits[i][3] & 0xfe;
236 }
237 /*
238 Leave white space in 32nd column of rows 8, 14, 15, and 23
239 to leave 16 pixel height upper, middle, and lower guides.
240 */
241 bitmap[toppixelrow + 8][(thiscol << 2) | 3] |= 1;
242 bitmap[toppixelrow + 14][(thiscol << 2) | 3] |= 1;
243 bitmap[toppixelrow + 15][(thiscol << 2) | 3] |= 1;
244 bitmap[toppixelrow + 23][(thiscol << 2) | 3] |= 1;
245 }
246 }
247 /*
248 Now write the appropriate bitmap file format, either
249 Wireless Bitmap or Microsoft Windows bitmap.
250 */
251 if (wbmp) { /* Write a Wireless Bitmap .wbmp format file */
252 /*
253 Write WBMP header
254 */
255 fprintf (outfp, "%c", 0x00); /* Type of image; always 0 (monochrome) */
256 fprintf (outfp, "%c", 0x00); /* Reserved; always 0 */
257 fprintf (outfp, "%c%c", 0x84, 0x40); /* Width = 576 pixels */
258 fprintf (outfp, "%c%c", 0x84, 0x20); /* Height = 544 pixels */
259 /*
260 Write bitmap image
261 */
262 for (toppixelrow=0; toppixelrow <= 17*32-1; toppixelrow++) {
263 for (j=0; j<18; j++) {
264 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) ]);
265 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) | 1]);
266 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) | 2]);
267 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) | 3]);
268 }
269 }
270 }
271 else { /* otherwise, write a Microsoft Windows .bmp format file */
272 /*
273 Write the .bmp file -- start with the header, then write the bitmap
274 */
275
276 /* 'B', 'M' appears at start of every .bmp file */
277 fprintf (outfp, "%c%c", 0x42, 0x4d);
278
279 /* Write file size in bytes */
280 filesize = 0x3E + bitmapsize;
281 fprintf (outfp, "%c", (unsigned char)((filesize ) & 0xff));
282 fprintf (outfp, "%c", (unsigned char)((filesize >> 0x08) & 0xff));
283 fprintf (outfp, "%c", (unsigned char)((filesize >> 0x10) & 0xff));
284 fprintf (outfp, "%c", (unsigned char)((filesize >> 0x18) & 0xff));
285
286 /* Reserved - 0's */
287 fprintf (outfp, "%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
288
289 /* Offset from start of file to bitmap data */
290 fprintf (outfp, "%c%c%c%c", 0x3E, 0x00, 0x00, 0x00);
291
292 /* Length of bitmap info header */
293 fprintf (outfp, "%c%c%c%c", 0x28, 0x00, 0x00, 0x00);
294
295 /* Width of bitmap in pixels */
296 fprintf (outfp, "%c%c%c%c", 0x40, 0x02, 0x00, 0x00);
297
298 /* Height of bitmap in pixels */
299 fprintf (outfp, "%c%c%c%c", 0x20, 0x02, 0x00, 0x00);
300
301 /* Planes in bitmap (fixed at 1) */
302 fprintf (outfp, "%c%c", 0x01, 0x00);
303
304 /* bits per pixel (1 = monochrome) */
305 fprintf (outfp, "%c%c", 0x01, 0x00);
306
307 /* Compression (0 = none) */
308 fprintf (outfp, "%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
309
310 /* Size of bitmap data in bytes */
311 fprintf (outfp, "%c", (unsigned char)((bitmapsize ) & 0xff));
312 fprintf (outfp, "%c", (unsigned char)((bitmapsize >> 0x08) & 0xff));
313 fprintf (outfp, "%c", (unsigned char)((bitmapsize >> 0x10) & 0xff));
314 fprintf (outfp, "%c", (unsigned char)((bitmapsize >> 0x18) & 0xff));
315
316 /* Horizontal resolution in pixels per meter */
317 fprintf (outfp, "%c%c%c%c", 0xC4, 0x0E, 0x00, 0x00);
318
319 /* Vertical resolution in pixels per meter */
320 fprintf (outfp, "%c%c%c%c", 0xC4, 0x0E, 0x00, 0x00);
321
322 /* Number of colors used */
323 fprintf (outfp, "%c%c%c%c", 0x02, 0x00, 0x00, 0x00);
324
325 /* Number of important colors */
326 fprintf (outfp, "%c%c%c%c", 0x02, 0x00, 0x00, 0x00);
327
328 /* The color black: B=0x00, G=0x00, R=0x00, Filler=0xFF */
329 fprintf (outfp, "%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
330
331 /* The color white: B=0xFF, G=0xFF, R=0xFF, Filler=0xFF */
332 fprintf (outfp, "%c%c%c%c", 0xFF, 0xFF, 0xFF, 0x00);
333
334 /*
335 Now write the raw data bits. Data is written from the lower
336 left-hand corner of the image to the upper right-hand corner
337 of the image.
338 */
339 for (toppixelrow=17*32-1; toppixelrow >= 0; toppixelrow--) {
340 for (j=0; j<18; j++) {
341 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) ]);
342 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) | 1]);
343 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) | 2]);
344
345 fprintf (outfp, "%c", bitmap[toppixelrow][(j<<2) | 3]);
346 }
347 }
348 }
349 exit (0);
350}
351
352
353/**
354 @brief Generate a bitmap for one glyph.
355
356 Convert the portion of a hex string after the ':' into a character bitmap.
357
358 If string is >= 128 characters, it will fill all 4 bytes per row.
359 If string is >= 64 characters and < 128, it will fill 2 bytes per row.
360 Otherwise, it will fill 1 byte per row.
361
362 @param[in] instring The character array containing the glyph bitmap.
363 @param[out] character Glyph bitmap, 8, 16, or 32 columns by 16 rows tall.
364 @return Always returns 0.
365*/
366 int
367 hex2bit (char *instring, unsigned char character[32][4])
368{
369
370 int i; /* current row in bitmap character */
371 int j; /* current character in input string */
372 int k; /* current byte in bitmap character */
373 int width; /* number of output bytes to fill - 1: 0, 1, 2, or 3 */
374
375 for (i=0; i<32; i++) /* erase previous character */
376 character[i][0] = character[i][1] = character[i][2] = character[i][3] = 0;
377 j=0; /* current location is at beginning of instring */
378
379 if (strlen (instring) <= 34) /* 32 + possible '\r', '\n' */
380 width = 0;
381 else if (strlen (instring) <= 66) /* 64 + possible '\r', '\n' */
382 width = 1;
383 else if (strlen (instring) <= 98) /* 96 + possible '\r', '\n' */
384 width = 3;
385 else /* the maximum allowed is quadruple-width */
386 width = 4;
387
388 k = (width > 1) ? 0 : 1; /* if width > double, start at index 1 else at 0 */
389
390 for (i=8; i<24; i++) { /* 16 rows per input character, rows 8..23 */
391 sscanf (&instring[j], "%2hhx", &character[i][k]);
392 j += 2;
393 if (width > 0) { /* add next pair of hex digits to this row */
394 sscanf (&instring[j], "%2hhx", &character[i][k+1]);
395 j += 2;
396 if (width > 1) { /* add next pair of hex digits to this row */
397 sscanf (&instring[j], "%2hhx", &character[i][k+2]);
398 j += 2;
399 if (width > 2) { /* quadruple-width is maximum width */
400 sscanf (&instring[j], "%2hhx", &character[i][k+3]);
401 j += 2;
402 }
403 }
404 }
405 }
406
407 return (0);
408}
409
410
411/**
412 @brief Initialize the bitmap grid.
413
414 @param[out] bitmap The bitmap to generate, with 32x32 pixel glyph areas.
415 @return Always returns 0.
416*/
417 int
418 init (unsigned char bitmap[17*32][18*4])
419{
420 int i, j;
421 unsigned char charbits[32][4]; /* bitmap for one character, 4 bytes/row */
422 unsigned toppixelrow;
423 unsigned thiscol;
424 unsigned char pnybble0, pnybble1, pnybble2, pnybble3;
425
426 for (i=0; i<18; i++) { /* bitmaps for '0'..'9', 'A'-'F', 'u', '+' */
427
428 hex2bit (&hex[i][5], charbits); /* convert hex string to 32*4 bitmap */
429
430 for (j=0; j<32; j++) hexbits[i][j] = ~charbits[j][1];
431 }
432
433 /*
434 Initialize bitmap to all white.
435 */
436 for (toppixelrow=0; toppixelrow < 17*32; toppixelrow++) {
437 for (thiscol=0; thiscol<18; thiscol++) {
438 bitmap[toppixelrow][(thiscol << 2) ] = 0xff;
439 bitmap[toppixelrow][(thiscol << 2) | 1] = 0xff;
440 bitmap[toppixelrow][(thiscol << 2) | 2] = 0xff;
441 bitmap[toppixelrow][(thiscol << 2) | 3] = 0xff;
442 }
443 }
444 /*
445 Write the "u+nnnn" table header in the upper left-hand corner,
446 where nnnn is the upper 16 bits of a 32-bit Unicode assignment.
447 */
448 pnybble3 = (unipage >> 20);
449 pnybble2 = (unipage >> 16) & 0xf;
450 pnybble1 = (unipage >> 12) & 0xf;
451 pnybble0 = (unipage >> 8) & 0xf;
452 for (i=0; i<32; i++) {
453 bitmap[i][1] = hexbits[16][i]; /* copy 'u' */
454 bitmap[i][2] = hexbits[17][i]; /* copy '+' */
455 bitmap[i][3] = hexbits[pnybble3][i];
456 bitmap[i][4] = hexbits[pnybble2][i];
457 bitmap[i][5] = hexbits[pnybble1][i];
458 bitmap[i][6] = hexbits[pnybble0][i];
459 }
460 /*
461 Write low-order 2 bytes of Unicode number assignments, as hex labels
462 */
463 pnybble3 = (unipage >> 4) & 0xf; /* Highest-order hex digit */
464 pnybble2 = (unipage ) & 0xf; /* Next highest-order hex digit */
465 /*
466 Write the column headers in bitmap[][] (row headers if flipped)
467 */
468 toppixelrow = 32 * 17 - 1; /* maximum pixel row number */
469 /*
470 Label the column headers. The hexbits[][] bytes are split across two
471 bitmap[][] entries to center a the hex digits in a column of 4 bytes.
472 OR highest byte with 0xf0 and lowest byte with 0x0f to make outer
473 nybbles white (0=black, 1-white).
474 */
475 for (i=0; i<16; i++) {
476 for (j=0; j<32; j++) {
477 if (flip) { /* transpose matrix */
478 bitmap[j][((i+2) << 2) | 0] = (hexbits[pnybble3][j] >> 4) | 0xf0;
479 bitmap[j][((i+2) << 2) | 1] = (hexbits[pnybble3][j] << 4) |
480 (hexbits[pnybble2][j] >> 4);
481 bitmap[j][((i+2) << 2) | 2] = (hexbits[pnybble2][j] << 4) |
482 (hexbits[i][j] >> 4);
483 bitmap[j][((i+2) << 2) | 3] = (hexbits[i][j] << 4) | 0x0f;
484 }
485 else {
486 bitmap[j][((i+2) << 2) | 1] = (hexbits[i][j] >> 4) | 0xf0;
487 bitmap[j][((i+2) << 2) | 2] = (hexbits[i][j] << 4) | 0x0f;
488 }
489 }
490 }
491 /*
492 Now use the single hex digit column graphics to label the row headers.
493 */
494 for (i=0; i<16; i++) {
495 toppixelrow = 32 * (i + 1) - 1; /* from bottom to top */
496
497 for (j=0; j<32; j++) {
498 if (!flip) { /* if not transposing matrix */
499 bitmap[toppixelrow + j][4] = hexbits[pnybble3][j];
500 bitmap[toppixelrow + j][5] = hexbits[pnybble2][j];
501 }
502 bitmap[toppixelrow + j][6] = hexbits[i][j];
503 }
504 }
505 /*
506 Now draw grid lines in bitmap, around characters we just copied.
507 */
508 /* draw vertical lines 2 pixels wide */
509 for (i=1*32; i<17*32; i++) {
510 if ((i & 0x1f) == 7)
511 i++;
512 else if ((i & 0x1f) == 14)
513 i += 2;
514 else if ((i & 0x1f) == 22)
515 i++;
516 for (j=1; j<18; j++) {
517 bitmap[i][(j << 2) | 3] &= 0xfe;
518 }
519 }
520 /* draw horizontal lines 1 pixel tall */
521 for (i=1*32-1; i<18*32-1; i+=32) {
522 for (j=2; j<18; j++) {
523 bitmap[i][(j << 2) ] = 0x00;
524 bitmap[i][(j << 2) | 1] = 0x81;
525 bitmap[i][(j << 2) | 2] = 0x81;
526 bitmap[i][(j << 2) | 3] = 0x00;
527 }
528 }
529 /* fill in top left corner pixel of grid */
530 bitmap[31][7] = 0xfe;
531
532 return (0);
533}
MAXBUF
#define MAXBUF
Maximum allowable input file line length - 1.
Definition: unibdf2hex.c:37
init
int init(unsigned char bitmap[17 *32][18 *4])
Initialize the bitmap grid.
Definition: unihex2bmp.c:418
main
int main(int argc, char *argv[])
The main function.
Definition: unihex2bmp.c:99
hex2bit
int hex2bit(char *instring, unsigned char character[32][4])
Generate a bitmap for one glyph.
Definition: unihex2bmp.c:367
unipage
unsigned unipage
Unicode page number, 0x00..0xff.
Definition: unihex2bmp.c:87
flip
int flip
Transpose entire matrix as in Unicode book.
Definition: unihex2bmp.c:88
hexbits
unsigned char hexbits[18][32]
The digits converted into bitmaps.
Definition: unihex2bmp.c:85
hex
char * hex[18]
GNU Unifont bitmaps for hexadecimal digits.
Definition: unihex2bmp.c:65