2 unihex2bmp - program to turn a GNU Unifont hex glyph page of 256 code
3 points into a Microsoft Bitmap (.bmp) or Wireless Bitmap file
5 Synopsis: unihex2bmp [-iin_file.hex] [-oout_file.bmp]
6 [-f] [-phex_page_num] [-w]
9 Author: Paul Hardy, unifoundry <at> unifoundry.com, December 2007
11 Copyright (C) 2007, 2008, 2013 Paul Hardy
15 This program is free software: you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation, either version 2 of the License, or
18 (at your option) any later version.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
37 These are the GNU Unifont hex strings for '0'-'9' and 'A'-'F',
38 for encoding as bit strings in row and column headers.
40 Looking at the final bitmap as a grid of 32*32 bit tiles, the
41 first row contains a hexadecimal character string of the first
42 3 hex digits in a 4 digit Unicode character name; the top column
43 contains a hex character string of the 4th (low-order) hex digit
44 of the Unicode character.
47 "0030:00000000182442424242424224180000", /* Hex digit 0 */
48 "0031:000000000818280808080808083E0000", /* Hex digit 1 */
49 "0032:000000003C4242020C102040407E0000", /* Hex digit 2 */
50 "0033:000000003C4242021C020242423C0000", /* Hex digit 3 */
51 "0034:00000000040C142444447E0404040000", /* Hex digit 4 */
52 "0035:000000007E4040407C020202423C0000", /* Hex digit 5 */
53 "0036:000000001C2040407C424242423C0000", /* Hex digit 6 */
54 "0037:000000007E0202040404080808080000", /* Hex digit 7 */
55 "0038:000000003C4242423C424242423C0000", /* Hex digit 8 */
56 "0039:000000003C4242423E02020204380000", /* Hex digit 9 */
57 "0041:0000000018242442427E424242420000", /* Hex digit A */
58 "0042:000000007C4242427C424242427C0000", /* Hex digit B */
59 "0043:000000003C42424040404042423C0000", /* Hex digit C */
60 "0044:00000000784442424242424244780000", /* Hex digit D */
61 "0045:000000007E4040407C404040407E0000", /* Hex digit E */
62 "0046:000000007E4040407C40404040400000", /* Hex digit F */
63 "0055:000000004242424242424242423C0000", /* Unicode 'U' */
64 "002B:0000000000000808087F080808000000" /* Unicode '+' */
66 unsigned char hexbits[18][32]; /* The above digits converted into bitmap */
68 unsigned unipage=0; /* Unicode page number, 0x00..0xff */
69 int flip=1; /* transpose entire matrix as in Unicode book */
73 int main(int argc, char *argv[]) {
75 int i, j; /* loop variables */
76 unsigned k0; /* temp Unicode char variable */
77 unsigned swap; /* temp variable for swapping values */
78 char inbuf[256]; /* input buffer */
79 // unsigned headersize=0x28; /* size of header (fixed in Windows) */
80 unsigned filesize; /* size of file in bytes */
81 unsigned bitmapsize; /* size of bitmap image in bytes */
82 unsigned thischar; /* the current character */
83 unsigned char thischarbyte; /* unsigned char lowest byte of Unicode char */
84 int thischarrow; /* row 0..15 where this character belongs */
85 int thiscol; /* column 0..15 where this character belongs */
86 int toppixelrow; /* pixel row, 0..16*32-1 */
87 unsigned lastpage=0; /* the last Unicode page read in font file */
88 int wbmp=0; /* set to 1 if writing .wbmp format file */
90 unsigned char bitmap[17*32][18*4]; /* final bitmap */
91 unsigned char charbits[32][4]; /* bitmap for one character, 4 bytes/row */
93 char *infile="", *outfile=""; /* names of input and output files */
94 FILE *infp, *outfp; /* file pointers of input and output files */
96 int init(); /* initializes bitmap row/col labeling, &c. */
97 int hex2bit(); /* convert hex string --> bitmap */
99 bitmapsize = 17*32*18*4; /* 17 rows by 18 cols, each 4 bytes */
102 for (i = 1; i < argc; i++) {
103 if (argv[i][0] == '-') { /* this is an option argument */
104 switch (argv[i][1]) {
105 case 'f': /* flip (transpose) glyphs in bitmap as in standard */
108 case 'i': /* name of input file */
109 infile = &argv[i][2];
111 case 'o': /* name of output file */
112 outfile = &argv[i][2];
114 case 'p': /* specify a Unicode page other than default of 0 */
115 sscanf(&argv[i][2], "%x", &unipage); /* Get Unicode page */
117 case 'w': /* write a .wbmp file instead of a .bmp file */
120 default: /* if unrecognized option, print list and exit */
121 fprintf(stderr, "\nSyntax:\n\n");
122 fprintf(stderr, " %s -p<Unicode_Page> ", argv[0]);
123 fprintf(stderr, "-i<Input_File> -o<Output_File> -w\n\n");
124 fprintf(stderr, " -w specifies .wbmp output instead of ");
125 fprintf(stderr, "default Windows .bmp output.\n\n");
126 fprintf(stderr, " -p is followed by 1 to 6 ");
127 fprintf(stderr, "Unicode page hex digits ");
128 fprintf(stderr, "(default is Page 0).\n\n");
129 fprintf(stderr, "\nExample:\n\n");
130 fprintf(stderr, " %s -p83 -iunifont.hex -ou83.bmp\n\n\n",
138 Make sure we can open any I/O files that were specified before
141 if (strlen(infile) > 0) {
142 if ((infp = fopen(infile, "r")) == NULL) {
143 fprintf(stderr, "Error: can't open %s for input.\n", infile);
150 if (strlen(outfile) > 0) {
151 if ((outfp = fopen(outfile, "w")) == NULL) {
152 fprintf(stderr, "Error: can't open %s for output.\n", outfile);
160 (void)init(bitmap); /* initialize bitmap with row/column headers, etc. */
163 Read in the characters in the page
165 while (lastpage <= unipage && fgets(inbuf, MAXBUF-1, infp) != NULL) {
166 sscanf(inbuf, "%x", &thischar);
167 lastpage = thischar >> 8; /* keep Unicode page to see if we can stop */
168 if (lastpage == unipage) {
169 thischarbyte = (unsigned char)(thischar & 0xff);
170 for (k0=0; inbuf[k0] != ':'; k0++);
172 hex2bit(&inbuf[k0], charbits); /* convert hex string to 32*4 bitmap */
175 Now write character bitmap upside-down in page array, to match
176 .bmp file order. In the .wbmp` and .bmp files, white is a '1'
177 bit and black is a '0' bit, so complement charbits[][].
180 thiscol = (thischarbyte & 0xf) + 2; /* column number will be 1..16 */
181 thischarrow = thischarbyte >> 4; /* charcter row number, 0..15 */
182 if (flip) { /* swap row and column placement */
184 thiscol = thischarrow;
186 thiscol += 2; /* column index starts at 1 */
187 thischarrow -= 2; /* row index starts at 0 */
189 toppixelrow = 32 * (thischarrow + 1) - 1; /* from bottom to top */
192 Copy the center of charbits[][] because hex characters only
193 occupy rows 8 to 23 and column byte 2 (and for 16 bit wide
194 characters, byte 3). The charbits[][] array was given 32 rows
195 and 4 column bytes for completeness in the beginning.
197 for (i=8; i<24; i++) {
198 bitmap[toppixelrow + i][(thiscol << 2) | 1] =
199 ~charbits[i][1] & 0xff;
200 bitmap[toppixelrow + i][(thiscol << 2) | 2] =
201 ~charbits[i][2] & 0xff;
206 Now write the appropriate bitmap file format, either
207 Wireless Bitmap or Microsoft Windows bitmap.
209 if (wbmp) { /* Write a Wireless Bitmap .wbmp format file */
213 fprintf(outfp, "%c", 0x00); /* Type of image; always 0 (monochrome) */
214 fprintf(outfp, "%c", 0x00); /* Reserved; always 0 */
215 fprintf(outfp, "%c%c", 0x84, 0x40); /* Width = 576 pixels */
216 fprintf(outfp, "%c%c", 0x84, 0x20); /* Height = 544 pixels */
220 for (toppixelrow=0; toppixelrow <= 17*32-1; toppixelrow++) {
221 for (j=0; j<18; j++) {
222 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) ]);
223 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) | 1]);
224 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) | 2]);
225 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) | 3]);
229 else { /* otherwise, write a Microsoft Windows .bmp format file */
231 Write the .bmp file -- start with the header, then write the bitmap
234 /* 'B', 'M' appears at start of every .bmp file */
235 fprintf(outfp, "%c%c", 0x42, 0x4d);
237 /* Write file size in bytes */
238 filesize = 0x3E + bitmapsize;
239 fprintf(outfp, "%c", (unsigned char)((filesize ) & 0xff));
240 fprintf(outfp, "%c", (unsigned char)((filesize >> 0x08) & 0xff));
241 fprintf(outfp, "%c", (unsigned char)((filesize >> 0x10) & 0xff));
242 fprintf(outfp, "%c", (unsigned char)((filesize >> 0x18) & 0xff));
245 fprintf(outfp, "%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
247 /* Offset from start of file to bitmap data */
248 fprintf(outfp, "%c%c%c%c", 0x3E, 0x00, 0x00, 0x00);
250 /* Length of bitmap info header */
251 fprintf(outfp, "%c%c%c%c", 0x28, 0x00, 0x00, 0x00);
253 /* Width of bitmap in pixels */
254 fprintf(outfp, "%c%c%c%c", 0x40, 0x02, 0x00, 0x00);
256 /* Height of bitmap in pixels */
257 fprintf(outfp, "%c%c%c%c", 0x20, 0x02, 0x00, 0x00);
259 /* Planes in bitmap (fixed at 1) */
260 fprintf(outfp, "%c%c", 0x01, 0x00);
262 /* bits per pixel (1 = monochrome) */
263 fprintf(outfp, "%c%c", 0x01, 0x00);
265 /* Compression (0 = none) */
266 fprintf(outfp, "%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
268 /* Size of bitmap data in bytes */
269 fprintf(outfp, "%c", (unsigned char)((bitmapsize ) & 0xff));
270 fprintf(outfp, "%c", (unsigned char)((bitmapsize >> 0x08) & 0xff));
271 fprintf(outfp, "%c", (unsigned char)((bitmapsize >> 0x10) & 0xff));
272 fprintf(outfp, "%c", (unsigned char)((bitmapsize >> 0x18) & 0xff));
274 /* Horizontal resolution in pixels per meter */
275 fprintf(outfp, "%c%c%c%c", 0xC4, 0x0E, 0x00, 0x00);
277 /* Vertical resolution in pixels per meter */
278 fprintf(outfp, "%c%c%c%c", 0xC4, 0x0E, 0x00, 0x00);
280 /* Number of colors used */
281 fprintf(outfp, "%c%c%c%c", 0x02, 0x00, 0x00, 0x00);
283 /* Number of important colors */
284 fprintf(outfp, "%c%c%c%c", 0x02, 0x00, 0x00, 0x00);
286 /* The color black: B=0x00, G=0x00, R=0x00, Filler=0xFF */
287 fprintf(outfp, "%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
289 /* The color white: B=0xFF, G=0xFF, R=0xFF, Filler=0xFF */
290 fprintf(outfp, "%c%c%c%c", 0xFF, 0xFF, 0xFF, 0x00);
293 Now write the raw data bits. Data is written from the lower
294 left-hand corner of the image to the upper right-hand corner
297 for (toppixelrow=17*32-1; toppixelrow >= 0; toppixelrow--) {
298 for (j=0; j<18; j++) {
299 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) ]);
300 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) | 1]);
301 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) | 2]);
303 fprintf(outfp, "%c", bitmap[toppixelrow][(j<<2) | 3]);
311 Convert the portion of a hex string after the ':' into a character bitmap.
313 If string is >= 128 characters, it will fill all 4 bytes per row.
314 If string is >= 64 characters and < 128, it will fill 2 bytes per row.
315 Otherwise, it will fill 1 byte per row.
317 int hex2bit(char *instring, unsigned char character[32][4]) {
319 int i; /* current row in bitmap character */
320 int j; /* current character in input string */
321 int k; /* current byte in bitmap character */
322 int width; /* number of output bytes to fill: 1, 2, or 4 */
324 for (i=0; i<32; i++) /* erase previous character */
325 character[i][0] = character[i][1] = character[i][2] = character[i][3] = 0;
326 j=0; /* current location is at beginning of instring */
328 // width = (strlen(instring) - 1) >> 4; /* 16 hex digits per 8 bytes */
330 if (strlen(instring) <= 34) /* 32 + possible '\r', '\n' */
332 else if (strlen(instring) <= 66) /* 64 + possible '\r', '\n' */
337 k = (width > 1) ? 0 : 1; /* if width < 3, start at index 1 else at 0 */
339 for (i=8; i<24; i++) { /* 16 rows per input character, rows 8..23 */
340 sscanf(&instring[j], "%2hhx", &character[i][k]);
342 if (width > 0) { /* add next pair of hex digits to this row */
343 sscanf(&instring[j], "%2hhx", &character[i][k+1]);
346 if (width > 1) { /* add 2 next pairs of hex digits to this row */
347 sscanf(&instring[j], "%2hhx", &character[i][k+2]);
349 sscanf(&instring[j], "%2hhx", &character[i][k+3]);
357 int init(unsigned char bitmap[17*32][18*4]) {
359 unsigned char charbits[32][4]; /* bitmap for one character, 4 bytes/row */
360 unsigned toppixelrow;
362 unsigned char pnybble0, pnybble1, pnybble2, pnybble3;
364 for (i=0; i<18; i++) { /* bitmaps for '0'..'9', 'A'-'F', 'u', '+' */
366 hex2bit(&hex[i][5], charbits); /* convert hex string to 32*4 bitmap */
368 for (j=0; j<32; j++) hexbits[i][j] = ~charbits[j][1];
372 Initialize bitmap to all white.
374 for (toppixelrow=0; toppixelrow < 17*32; toppixelrow++) {
375 for (thiscol=0; thiscol<18; thiscol++) {
376 bitmap[toppixelrow][(thiscol << 2) ] = 0xff;
377 bitmap[toppixelrow][(thiscol << 2) | 1] = 0xff;
378 bitmap[toppixelrow][(thiscol << 2) | 2] = 0xff;
379 bitmap[toppixelrow][(thiscol << 2) | 3] = 0xff;
383 Write the "u+nnnn" table header in the upper left-hand corner,
384 where nnnn is the upper 16 bits of a 32-bit Unicode assignment.
386 pnybble3 = (unipage >> 20);
387 pnybble2 = (unipage >> 16) & 0xf;
388 pnybble1 = (unipage >> 12) & 0xf;
389 pnybble0 = (unipage >> 8) & 0xf;
390 for (i=0; i<32; i++) {
391 bitmap[i][1] = hexbits[16][i]; /* copy 'u' */
392 bitmap[i][2] = hexbits[17][i]; /* copy '+' */
393 bitmap[i][3] = hexbits[pnybble3][i];
394 bitmap[i][4] = hexbits[pnybble2][i];
395 bitmap[i][5] = hexbits[pnybble1][i];
396 bitmap[i][6] = hexbits[pnybble0][i];
399 Write low-order 2 bytes of Unicode number assignments, as hex labels
401 pnybble3 = (unipage >> 4) & 0xf; /* Highest-order hex digit */
402 pnybble2 = (unipage ) & 0xf; /* Next highest-order hex digit */
404 Write the column headers in bitmap[][] (row headers if flipped)
406 toppixelrow = 32 * 17 - 1; /* maximum pixel row number */
408 Label the column headers. The hexbits[][] bytes are split across two
409 bitmap[][] entries to center a the hex digits in a column of 4 bytes.
410 OR highest byte with 0xf0 and lowest byte with 0x0f to make outer
411 nybbles white (0=black, 1-white).
413 for (i=0; i<16; i++) {
414 for (j=0; j<32; j++) {
415 if (flip) { /* transpose matrix */
416 bitmap[j][((i+2) << 2) | 0] = (hexbits[pnybble3][j] >> 4) | 0xf0;
417 bitmap[j][((i+2) << 2) | 1] = (hexbits[pnybble3][j] << 4) |
418 (hexbits[pnybble2][j] >> 4);
419 bitmap[j][((i+2) << 2) | 2] = (hexbits[pnybble2][j] << 4) |
420 (hexbits[i][j] >> 4);
421 bitmap[j][((i+2) << 2) | 3] = (hexbits[i][j] << 4) | 0x0f;
424 bitmap[j][((i+2) << 2) | 1] = (hexbits[i][j] >> 4) | 0xf0;
425 bitmap[j][((i+2) << 2) | 2] = (hexbits[i][j] << 4) | 0x0f;
430 Now use the single hex digit column graphics to label the row headers.
432 for (i=0; i<16; i++) {
433 toppixelrow = 32 * (i + 1) - 1; /* from bottom to top */
435 for (j=0; j<32; j++) {
436 if (!flip) { /* if not transposing matrix */
437 bitmap[toppixelrow + j][4] = hexbits[pnybble3][j];
438 bitmap[toppixelrow + j][5] = hexbits[pnybble2][j];
440 bitmap[toppixelrow + j][6] = hexbits[i][j];
444 Now draw grid lines in bitmap, around characters we just copied.
446 /* draw vertical lines 2 pixels wide */
447 for (i=1*32; i<17*32; i++) {
450 else if ((i & 0x1f) == 14)
452 else if ((i & 0x1f) == 22)
454 for (j=1; j<18; j++) {
455 bitmap[i][(j << 2) | 3] &= 0xfe;
458 /* draw horizontal lines 2 pixels tall */
459 for (i=1*32-1; i<18*32-1; i+=32) {
460 for (j=2; j<18; j++) {
461 bitmap[i][(j << 2) ] = 0x00;
462 bitmap[i][(j << 2) | 1] = 0x81;
463 bitmap[i][(j << 2) | 2] = 0x81;
464 bitmap[i][(j << 2) | 3] = 0x00;
467 /* fill in top left corner pixel of grid */
468 bitmap[31][7] = 0xfe;