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