GNU Unifont  15.1.01
Pan-Unicode font with complete Unicode Plane 0 coverage and partial coverage of higher planes
unifontpic.c
Go to the documentation of this file.
1 /**
2  @file unifontpic.c
3 
4  @brief unifontpic - See the "Big Picture": the entire Unifont
5  in one BMP bitmap
6 
7  @author Paul Hardy, 2013
8 
9  @copyright Copyright (C) 2013, 2017 Paul Hardy
10 */
11 /*
12  LICENSE:
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 2 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <http://www.gnu.org/licenses/>.
26 */
27 
28 /*
29  11 June 2017 [Paul Hardy]:
30  - Modified to take glyphs that are 24 or 32 pixels wide and
31  compress them horizontally by 50%.
32 
33  8 July 2017 [Paul Hardy]:
34  - Modified to print Unifont charts above Unicode Plane 0.
35  - Adds "-P" option to specify Unicode plane in decimal,
36  as "-P0" through "-P17". Omitting this argument uses
37  plane 0 as the default.
38  - Appends Unicode plane number to chart title.
39  - Reads in "unifontpic.h", which was added mainly to
40  store ASCII chart title glyphs in an embedded array
41  rather than requiring these ASCII glyphs to be in
42  the ".hex" file that is read in for the chart body
43  (which was the case previously, when all that was
44  able to print was Unicode place 0).
45  - Fixes truncated header in long bitmap format, making
46  the long chart title glyphs single-spaced. This leaves
47  room for the Unicode plane to appear even in the narrow
48  chart title of the "long" format chart. The wide chart
49  title still has double-spaced ASCII glyphs.
50  - Adjusts centering of title on long and wide charts.
51 
52  11 May 2019 [Paul Hardy]:
53  - Changed strncpy calls to memcpy.
54  - Added "HDR_LEN" to define length of header string
55  for use in snprintf function call.
56  - Changed sprintf function calls to snprintf function
57  calls for writing chart header string.
58 */
59 
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include "unifontpic.h"
65 
66 /** Define length of header string for top of chart. */
67 #define HDR_LEN 33
68 
69 
70 /*
71  Stylistic Note:
72 
73  Many variables in this program use multiple words scrunched
74  together, with each word starting with an upper-case letter.
75  This is only done to match the canonical field names in the
76  Windows Bitmap Graphics spec.
77 */
78 
79 /**
80  @brief The main function.
81 
82  @param[in] argc The count of command line arguments.
83  @param[in] argv Pointer to array of command line arguments.
84  @return This program exits with status EXIT_SUCCESS.
85 */
86 int
87 main (int argc, char **argv)
88 {
89  /* Input line buffer */
90  char instring[MAXSTRING];
91 
92  /* long and dpi are set from command-line options */
93  int wide=1; /* =1 for a 256x256 grid, =0 for a 16x4096 grid */
94  int dpi=96; /* change for 256x256 grid to fit paper if desired */
95  int tinynum=0; /* whether to use tiny labels for 256x256 grid */
96 
97  int i, j; /* loop variables */
98 
99  int plane=0; /* Unicode plane, 0..17; Plane 0 is default */
100  /* 16 pixel rows for each of 65,536 glyphs in a Unicode plane */
101  int plane_array[0x10000][16];
102 
103  void gethex();
104  void genlongbmp();
105  void genwidebmp();
106 
107  if (argc > 1) {
108  for (i = 1; i < argc; i++) {
109  if (strncmp (argv[i],"-l",2) == 0) { /* long display */
110  wide = 0;
111  }
112  else if (strncmp (argv[i],"-d",2) == 0) {
113  dpi = atoi (&argv[i][2]); /* dots/inch specified on command line */
114  }
115  else if (strncmp (argv[i],"-t",2) == 0) {
116  tinynum = 1;
117  }
118  else if (strncmp (argv[i],"-P",2) == 0) {
119  /* Get Unicode plane */
120  for (j = 2; argv[i][j] != '\0'; j++) {
121  if (argv[i][j] < '0' || argv[i][j] > '9') {
122  fprintf (stderr,
123  "ERROR: Specify Unicode plane as decimal number.\n\n");
124  exit (EXIT_FAILURE);
125  }
126  }
127  plane = atoi (&argv[i][2]); /* Unicode plane, 0..17 */
128  if (plane < 0 || plane > 17) {
129  fprintf (stderr,
130  "ERROR: Plane out of Unicode range [0,17].\n\n");
131  exit (EXIT_FAILURE);
132  }
133  }
134  }
135  }
136 
137 
138  /*
139  Initialize the ASCII bitmap array for chart titles
140  */
141  for (i = 0; i < 128; i++) {
142  gethex (ascii_hex[i], plane_array, 0); /* convert Unifont hexadecimal string to bitmap */
143  for (j = 0; j < 16; j++) ascii_bits[i][j] = plane_array[i][j];
144  }
145 
146 
147  /*
148  Read in the Unifont hex file to render from standard input
149  */
150  memset ((void *)plane_array, 0, 0x10000 * 16 * sizeof (int));
151  while (fgets (instring, MAXSTRING, stdin) != NULL) {
152  gethex (instring, plane_array, plane); /* read .hex input file and fill plane_array with glyph data */
153  } /* while not EOF */
154 
155 
156  /*
157  Write plane_array glyph data to BMP file as wide or long bitmap.
158  */
159  if (wide) {
160  genwidebmp (plane_array, dpi, tinynum, plane);
161  }
162  else {
163  genlongbmp (plane_array, dpi, tinynum, plane);
164  }
165 
166  exit (EXIT_SUCCESS);
167 }
168 
169 
170 /**
171  @brief Output a 4-byte integer in little-endian order.
172 
173  @param[in] thisword The 4-byte integer to output as binary data.
174 */
175 void
176 output4 (int thisword)
177 {
178 
179  putchar ( thisword & 0xFF);
180  putchar ((thisword >> 8) & 0xFF);
181  putchar ((thisword >> 16) & 0xFF);
182  putchar ((thisword >> 24) & 0xFF);
183 
184  return;
185 }
186 
187 
188 /**
189  @brief Output a 2-byte integer in little-endian order.
190 
191  @param[in] thisword The 2-byte integer to output as binary data.
192 */
193 void
194 output2 (int thisword)
195 {
196 
197  putchar ( thisword & 0xFF);
198  putchar ((thisword >> 8) & 0xFF);
199 
200  return;
201 }
202 
203 
204 /**
205  @brief Read a Unifont .hex-format input file from stdin.
206 
207  Each glyph can be 2, 4, 6, or 8 ASCII hexadecimal digits wide.
208  Glyph height is fixed at 16 pixels.
209 
210  @param[in] instring One line from a Unifont .hex-format file.
211  @param[in,out] plane_array Bitmap for this plane, one bitmap row per element.
212  @param[in] plane The Unicode plane, 0..17.
213 */
214 void
215 gethex (char *instring, int plane_array[0x10000][16], int plane)
216 {
217  char *bitstring; /* pointer into instring for glyph bitmap */
218  int i; /* loop variable */
219  int codept; /* the Unicode code point of the current glyph */
220  int glyph_plane; /* Unicode plane of current glyph */
221  int ndigits; /* number of ASCII hexadecimal digits in glyph */
222  int bytespl; /* bytes per line of pixels in a glyph */
223  int temprow; /* 1 row of a quadruple-width glyph */
224  int newrow; /* 1 row of double-width output pixels */
225  unsigned bitmask; /* to mask off 2 bits of long width glyph */
226 
227  /*
228  Read each input line and place its glyph into the bit array.
229  */
230  sscanf (instring, "%X", &codept);
231  glyph_plane = codept >> 16;
232  if (glyph_plane == plane) {
233  codept &= 0xFFFF; /* array index will only have 16 bit address */
234  /* find the colon separator */
235  for (i = 0; (i < 9) && (instring[i] != ':'); i++);
236  i++; /* position past it */
237  bitstring = &instring[i];
238  ndigits = strlen (bitstring);
239  /* don't count '\n' at end of line if present */
240  if (bitstring[ndigits - 1] == '\n') ndigits--;
241  bytespl = ndigits >> 5; /* 16 rows per line, 2 digits per byte */
242 
243  if (bytespl >= 1 && bytespl <= 4) {
244  for (i = 0; i < 16; i++) { /* 16 rows per glyph */
245  /* Read correct number of hexadecimal digits given glyph width */
246  switch (bytespl) {
247  case 1: sscanf (bitstring, "%2X", &temprow);
248  bitstring += 2;
249  temprow <<= 8; /* left-justify single-width glyph */
250  break;
251  case 2: sscanf (bitstring, "%4X", &temprow);
252  bitstring += 4;
253  break;
254  /* cases 3 and 4 widths will be compressed by 50% (see below) */
255  case 3: sscanf (bitstring, "%6X", &temprow);
256  bitstring += 6;
257  temprow <<= 8; /* left-justify */
258  break;
259  case 4: sscanf (bitstring, "%8X", &temprow);
260  bitstring += 8;
261  break;
262  } /* switch on number of bytes per row */
263  /* compress glyph width by 50% if greater than double-width */
264  if (bytespl > 2) {
265  newrow = 0x0000;
266  /* mask off 2 bits at a time to convert each pair to 1 bit out */
267  for (bitmask = 0xC0000000; bitmask != 0; bitmask >>= 2) {
268  newrow <<= 1;
269  if ((temprow & bitmask) != 0) newrow |= 1;
270  }
271  temprow = newrow;
272  } /* done conditioning glyphs beyond double-width */
273  plane_array[codept][i] = temprow; /* store glyph bitmap for output */
274  } /* for each row */
275  } /* if 1 to 4 bytes per row/line */
276  } /* if this is the plane we are seeking */
277 
278  return;
279 }
280 
281 
282 /**
283  @brief Generate the BMP output file in long format.
284 
285  This function generates the BMP output file from a bitmap parameter.
286  This is a long bitmap, 16 glyphs wide by 4,096 glyphs tall.
287 
288  @param[in] plane_array The array of glyph bitmaps for a plane.
289  @param[in] dpi Dots per inch, for encoding in the BMP output file header.
290  @param[in] tinynum Whether to generate tiny numbers in wide grid (unused).
291  @param[in] plane The Unicode plane, 0..17.
292 */
293 void
294 genlongbmp (int plane_array[0x10000][16], int dpi, int tinynum, int plane)
295 {
296 
297  char header_string[HDR_LEN]; /* centered header */
298  char raw_header[HDR_LEN]; /* left-aligned header */
299  int header[16][16]; /* header row, for chart title */
300  int hdrlen; /* length of HEADER_STRING */
301  int startcol; /* column to start printing header, for centering */
302 
303  unsigned leftcol[0x1000][16]; /* code point legend on left side of chart */
304  int d1, d2, d3, d4; /* digits for filling leftcol[][] legend */
305  int codept; /* current starting code point for legend */
306  int thisrow; /* glyph row currently being rendered */
307  unsigned toprow[16][16]; /* code point legend on top of chart */
308  int digitrow; /* row we're in (0..4) for the above hexdigit digits */
309 
310  /*
311  DataOffset = BMP Header bytes + InfoHeader bytes + ColorTable bytes.
312  */
313  int DataOffset = 14 + 40 + 8; /* fixed size for monochrome BMP */
314  int ImageSize;
315  int FileSize;
316  int Width, Height; /* bitmap image width and height in pixels */
317  int ppm; /* integer pixels per meter */
318 
319  int i, j, k;
320 
321  unsigned bytesout;
322 
323  void output4(int), output2(int);
324 
325  /*
326  Image width and height, in pixels.
327 
328  N.B.: Width must be an even multiple of 32 pixels, or 4 bytes.
329  */
330  Width = 18 * 16; /* (2 legend + 16 glyphs) * 16 pixels/glyph */
331  Height = 4099 * 16; /* (1 header + 4096 glyphs) * 16 rows/glyph */
332 
333  ImageSize = Height * (Width / 8); /* in bytes, calculated from pixels */
334 
335  FileSize = DataOffset + ImageSize;
336 
337  /* convert dots/inch to pixels/meter */
338  if (dpi == 0) dpi = 96;
339  ppm = (int)((double)dpi * 100.0 / 2.54 + 0.5);
340 
341  /*
342  Generate the BMP Header
343  */
344  putchar ('B');
345  putchar ('M');
346 
347  /*
348  Calculate file size:
349 
350  BMP Header + InfoHeader + Color Table + Raster Data
351  */
352  output4 (FileSize); /* FileSize */
353  output4 (0x0000); /* reserved */
354 
355  /* Calculate DataOffset */
356  output4 (DataOffset);
357 
358  /*
359  InfoHeader
360  */
361  output4 (40); /* Size of InfoHeader */
362  output4 (Width); /* Width of bitmap in pixels */
363  output4 (Height); /* Height of bitmap in pixels */
364  output2 (1); /* Planes (1 plane) */
365  output2 (1); /* BitCount (1 = monochrome) */
366  output4 (0); /* Compression (0 = none) */
367  output4 (ImageSize); /* ImageSize, in bytes */
368  output4 (ppm); /* XpixelsPerM (96 dpi = 3780 pixels/meter) */
369  output4 (ppm); /* YpixelsPerM (96 dpi = 3780 pixels/meter) */
370  output4 (2); /* ColorsUsed (= 2) */
371  output4 (2); /* ColorsImportant (= 2) */
372  output4 (0x00000000); /* black (reserved, B, G, R) */
373  output4 (0x00FFFFFF); /* white (reserved, B, G, R) */
374 
375  /*
376  Create header row bits.
377  */
378  snprintf (raw_header, HDR_LEN, "%s Plane %d", HEADER_STRING, plane);
379  memset ((void *)header, 0, 16 * 16 * sizeof (int)); /* fill with white */
380  memset ((void *)header_string, ' ', 32 * sizeof (char)); /* 32 spaces */
381  header_string[32] = '\0'; /* null-terminated */
382 
383  hdrlen = strlen (raw_header);
384  if (hdrlen > 32) hdrlen = 32; /* only 32 columns to print header */
385  startcol = 16 - ((hdrlen + 1) >> 1); /* to center header */
386  /* center up to 32 chars */
387  memcpy (&header_string[startcol], raw_header, hdrlen);
388 
389  /* Copy each letter's bitmap from the plane_array[][] we constructed. */
390  /* Each glyph must be single-width, to fit two glyphs in 16 pixels */
391  for (j = 0; j < 16; j++) {
392  for (i = 0; i < 16; i++) {
393  header[i][j] =
394  (ascii_bits[header_string[j+j ] & 0x7F][i] & 0xFF00) |
395  (ascii_bits[header_string[j+j+1] & 0x7F][i] >> 8);
396  }
397  }
398 
399  /*
400  Create the left column legend.
401  */
402  memset ((void *)leftcol, 0, 4096 * 16 * sizeof (unsigned));
403 
404  for (codept = 0x0000; codept < 0x10000; codept += 0x10) {
405  d1 = (codept >> 12) & 0xF; /* most significant hex digit */
406  d2 = (codept >> 8) & 0xF;
407  d3 = (codept >> 4) & 0xF;
408 
409  thisrow = codept >> 4; /* rows of 16 glyphs */
410 
411  /* fill in first and second digits */
412  for (digitrow = 0; digitrow < 5; digitrow++) {
413  leftcol[thisrow][2 + digitrow] =
414  (hexdigit[d1][digitrow] << 10) |
415  (hexdigit[d2][digitrow] << 4);
416  }
417 
418  /* fill in third digit */
419  for (digitrow = 0; digitrow < 5; digitrow++) {
420  leftcol[thisrow][9 + digitrow] = hexdigit[d3][digitrow] << 10;
421  }
422  leftcol[thisrow][9 + 4] |= 0xF << 4; /* underscore as 4th digit */
423 
424  for (i = 0; i < 15; i ++) {
425  leftcol[thisrow][i] |= 0x00000002; /* right border */
426  }
427 
428  leftcol[thisrow][15] = 0x0000FFFE; /* bottom border */
429 
430  if (d3 == 0xF) { /* 256-point boundary */
431  leftcol[thisrow][15] |= 0x00FF0000; /* longer tic mark */
432  }
433 
434  if ((thisrow % 0x40) == 0x3F) { /* 1024-point boundary */
435  leftcol[thisrow][15] |= 0xFFFF0000; /* longest tic mark */
436  }
437  }
438 
439  /*
440  Create the top row legend.
441  */
442  memset ((void *)toprow, 0, 16 * 16 * sizeof (unsigned));
443 
444  for (codept = 0x0; codept <= 0xF; codept++) {
445  d1 = (codept >> 12) & 0xF; /* most significant hex digit */
446  d2 = (codept >> 8) & 0xF;
447  d3 = (codept >> 4) & 0xF;
448  d4 = codept & 0xF; /* least significant hex digit */
449 
450  /* fill in last digit */
451  for (digitrow = 0; digitrow < 5; digitrow++) {
452  toprow[6 + digitrow][codept] = hexdigit[d4][digitrow] << 6;
453  }
454  }
455 
456  for (j = 0; j < 16; j++) {
457  /* force bottom pixel row to be white, for separation from glyphs */
458  toprow[15][j] = 0x0000;
459  }
460 
461  /* 1 pixel row with left-hand legend line */
462  for (j = 0; j < 16; j++) {
463  toprow[14][j] |= 0xFFFF;
464  }
465 
466  /* 14 rows with line on left to fill out this character row */
467  for (i = 13; i >= 0; i--) {
468  for (j = 0; j < 16; j++) {
469  toprow[i][j] |= 0x0001;
470  }
471  }
472 
473  /*
474  Now write the raster image.
475 
476  XOR each byte with 0xFF because black = 0, white = 1 in BMP.
477  */
478 
479  /* Write the glyphs, bottom-up, left-to-right, in rows of 16 (i.e., 0x10) */
480  for (i = 0xFFF0; i >= 0; i -= 0x10) {
481  thisrow = i >> 4; /* 16 glyphs per row */
482  for (j = 15; j >= 0; j--) {
483  /* left-hand legend */
484  putchar ((~leftcol[thisrow][j] >> 24) & 0xFF);
485  putchar ((~leftcol[thisrow][j] >> 16) & 0xFF);
486  putchar ((~leftcol[thisrow][j] >> 8) & 0xFF);
487  putchar ( ~leftcol[thisrow][j] & 0xFF);
488  /* Unifont glyph */
489  for (k = 0; k < 16; k++) {
490  bytesout = ~plane_array[i+k][j] & 0xFFFF;
491  putchar ((bytesout >> 8) & 0xFF);
492  putchar ( bytesout & 0xFF);
493  }
494  }
495  }
496 
497  /*
498  Write the top legend.
499  */
500  /* i == 15: bottom pixel row of header is output here */
501  /* left-hand legend: solid black line except for right-most pixel */
502  putchar (0x00);
503  putchar (0x00);
504  putchar (0x00);
505  putchar (0x01);
506  for (j = 0; j < 16; j++) {
507  putchar ((~toprow[15][j] >> 8) & 0xFF);
508  putchar ( ~toprow[15][j] & 0xFF);
509  }
510 
511  putchar (0xFF);
512  putchar (0xFF);
513  putchar (0xFF);
514  putchar (0xFC);
515  for (j = 0; j < 16; j++) {
516  putchar ((~toprow[14][j] >> 8) & 0xFF);
517  putchar ( ~toprow[14][j] & 0xFF);
518  }
519 
520  for (i = 13; i >= 0; i--) {
521  putchar (0xFF);
522  putchar (0xFF);
523  putchar (0xFF);
524  putchar (0xFD);
525  for (j = 0; j < 16; j++) {
526  putchar ((~toprow[i][j] >> 8) & 0xFF);
527  putchar ( ~toprow[i][j] & 0xFF);
528  }
529  }
530 
531  /*
532  Write the header.
533  */
534 
535  /* 7 completely white rows */
536  for (i = 7; i >= 0; i--) {
537  for (j = 0; j < 18; j++) {
538  putchar (0xFF);
539  putchar (0xFF);
540  }
541  }
542 
543  for (i = 15; i >= 0; i--) {
544  /* left-hand legend */
545  putchar (0xFF);
546  putchar (0xFF);
547  putchar (0xFF);
548  putchar (0xFF);
549  /* header glyph */
550  for (j = 0; j < 16; j++) {
551  bytesout = ~header[i][j] & 0xFFFF;
552  putchar ((bytesout >> 8) & 0xFF);
553  putchar ( bytesout & 0xFF);
554  }
555  }
556 
557  /* 8 completely white rows at very top */
558  for (i = 7; i >= 0; i--) {
559  for (j = 0; j < 18; j++) {
560  putchar (0xFF);
561  putchar (0xFF);
562  }
563  }
564 
565  return;
566 }
567 
568 
569 /**
570  @brief Generate the BMP output file in wide format.
571 
572  This function generates the BMP output file from a bitmap parameter.
573  This is a wide bitmap, 256 glyphs wide by 256 glyphs tall.
574 
575  @param[in] plane_array The array of glyph bitmaps for a plane.
576  @param[in] dpi Dots per inch, for encoding in the BMP output file header.
577  @param[in] tinynum Whether to generate tiny numbers in 256x256 grid.
578  @param[in] plane The Unicode plane, 0..17.
579 */
580 void
581 genwidebmp (int plane_array[0x10000][16], int dpi, int tinynum, int plane)
582 {
583 
584  char header_string[257];
585  char raw_header[HDR_LEN];
586  int header[16][256]; /* header row, for chart title */
587  int hdrlen; /* length of HEADER_STRING */
588  int startcol; /* column to start printing header, for centering */
589 
590  unsigned leftcol[0x100][16]; /* code point legend on left side of chart */
591  int d1, d2, d3, d4; /* digits for filling leftcol[][] legend */
592  int codept; /* current starting code point for legend */
593  int thisrow; /* glyph row currently being rendered */
594  unsigned toprow[32][256]; /* code point legend on top of chart */
595  int digitrow; /* row we're in (0..4) for the above hexdigit digits */
596  int hexalpha1, hexalpha2; /* to convert hex digits to ASCII */
597 
598  /*
599  DataOffset = BMP Header bytes + InfoHeader bytes + ColorTable bytes.
600  */
601  int DataOffset = 14 + 40 + 8; /* fixed size for monochrome BMP */
602  int ImageSize;
603  int FileSize;
604  int Width, Height; /* bitmap image width and height in pixels */
605  int ppm; /* integer pixels per meter */
606 
607  int i, j, k;
608 
609  unsigned bytesout;
610 
611  void output4(int), output2(int);
612 
613  /*
614  Image width and height, in pixels.
615 
616  N.B.: Width must be an even multiple of 32 pixels, or 4 bytes.
617  */
618  Width = 258 * 16; /* ( 2 legend + 256 glyphs) * 16 pixels/glyph */
619  Height = 260 * 16; /* (2 header + 2 legend + 256 glyphs) * 16 rows/glyph */
620 
621  ImageSize = Height * (Width / 8); /* in bytes, calculated from pixels */
622 
623  FileSize = DataOffset + ImageSize;
624 
625  /* convert dots/inch to pixels/meter */
626  if (dpi == 0) dpi = 96;
627  ppm = (int)((double)dpi * 100.0 / 2.54 + 0.5);
628 
629  /*
630  Generate the BMP Header
631  */
632  putchar ('B');
633  putchar ('M');
634  /*
635  Calculate file size:
636 
637  BMP Header + InfoHeader + Color Table + Raster Data
638  */
639  output4 (FileSize); /* FileSize */
640  output4 (0x0000); /* reserved */
641  /* Calculate DataOffset */
642  output4 (DataOffset);
643 
644  /*
645  InfoHeader
646  */
647  output4 (40); /* Size of InfoHeader */
648  output4 (Width); /* Width of bitmap in pixels */
649  output4 (Height); /* Height of bitmap in pixels */
650  output2 (1); /* Planes (1 plane) */
651  output2 (1); /* BitCount (1 = monochrome) */
652  output4 (0); /* Compression (0 = none) */
653  output4 (ImageSize); /* ImageSize, in bytes */
654  output4 (ppm); /* XpixelsPerM (96 dpi = 3780 pixels/meter) */
655  output4 (ppm); /* YpixelsPerM (96 dpi = 3780 pixels/meter) */
656  output4 (2); /* ColorsUsed (= 2) */
657  output4 (2); /* ColorsImportant (= 2) */
658  output4 (0x00000000); /* black (reserved, B, G, R) */
659  output4 (0x00FFFFFF); /* white (reserved, B, G, R) */
660 
661  /*
662  Create header row bits.
663  */
664  snprintf (raw_header, HDR_LEN, "%s Plane %d", HEADER_STRING, plane);
665  memset ((void *)header, 0, 256 * 16 * sizeof (int)); /* fill with white */
666  memset ((void *)header_string, ' ', 256 * sizeof (char)); /* 256 spaces */
667  header_string[256] = '\0'; /* null-terminated */
668 
669  hdrlen = strlen (raw_header);
670  /* Wide bitmap can print 256 columns, but limit to 32 columns for long bitmap. */
671  if (hdrlen > 32) hdrlen = 32;
672  startcol = 127 - ((hdrlen - 1) >> 1); /* to center header */
673  /* center up to 32 chars */
674  memcpy (&header_string[startcol], raw_header, hdrlen);
675 
676  /* Copy each letter's bitmap from the plane_array[][] we constructed. */
677  for (j = 0; j < 256; j++) {
678  for (i = 0; i < 16; i++) {
679  header[i][j] = ascii_bits[header_string[j] & 0x7F][i];
680  }
681  }
682 
683  /*
684  Create the left column legend.
685  */
686  memset ((void *)leftcol, 0, 256 * 16 * sizeof (unsigned));
687 
688  for (codept = 0x0000; codept < 0x10000; codept += 0x100) {
689  d1 = (codept >> 12) & 0xF; /* most significant hex digit */
690  d2 = (codept >> 8) & 0xF;
691 
692  thisrow = codept >> 8; /* rows of 256 glyphs */
693 
694  /* fill in first and second digits */
695 
696  if (tinynum) { /* use 4x5 pixel glyphs */
697  for (digitrow = 0; digitrow < 5; digitrow++) {
698  leftcol[thisrow][6 + digitrow] =
699  (hexdigit[d1][digitrow] << 10) |
700  (hexdigit[d2][digitrow] << 4);
701  }
702  }
703  else { /* bigger numbers -- use glyphs from Unifont itself */
704  /* convert hexadecimal digits to ASCII equivalent */
705  hexalpha1 = d1 < 0xA ? '0' + d1 : 'A' + d1 - 0xA;
706  hexalpha2 = d2 < 0xA ? '0' + d2 : 'A' + d2 - 0xA;
707 
708  for (i = 0 ; i < 16; i++) {
709  leftcol[thisrow][i] =
710  (ascii_bits[hexalpha1][i] << 2) |
711  (ascii_bits[hexalpha2][i] >> 6);
712  }
713  }
714 
715  for (i = 0; i < 15; i ++) {
716  leftcol[thisrow][i] |= 0x00000002; /* right border */
717  }
718 
719  leftcol[thisrow][15] = 0x0000FFFE; /* bottom border */
720 
721  if (d2 == 0xF) { /* 4096-point boundary */
722  leftcol[thisrow][15] |= 0x00FF0000; /* longer tic mark */
723  }
724 
725  if ((thisrow % 0x40) == 0x3F) { /* 16,384-point boundary */
726  leftcol[thisrow][15] |= 0xFFFF0000; /* longest tic mark */
727  }
728  }
729 
730  /*
731  Create the top row legend.
732  */
733  memset ((void *)toprow, 0, 32 * 256 * sizeof (unsigned));
734 
735  for (codept = 0x00; codept <= 0xFF; codept++) {
736  d3 = (codept >> 4) & 0xF;
737  d4 = codept & 0xF; /* least significant hex digit */
738 
739  if (tinynum) {
740  for (digitrow = 0; digitrow < 5; digitrow++) {
741  toprow[16 + 6 + digitrow][codept] =
742  (hexdigit[d3][digitrow] << 10) |
743  (hexdigit[d4][digitrow] << 4);
744  }
745  }
746  else {
747  /* convert hexadecimal digits to ASCII equivalent */
748  hexalpha1 = d3 < 0xA ? '0' + d3 : 'A' + d3 - 0xA;
749  hexalpha2 = d4 < 0xA ? '0' + d4 : 'A' + d4 - 0xA;
750  for (i = 0 ; i < 16; i++) {
751  toprow[14 + i][codept] =
752  (ascii_bits[hexalpha1][i] ) |
753  (ascii_bits[hexalpha2][i] >> 7);
754  }
755  }
756  }
757 
758  for (j = 0; j < 256; j++) {
759  /* force bottom pixel row to be white, for separation from glyphs */
760  toprow[16 + 15][j] = 0x0000;
761  }
762 
763  /* 1 pixel row with left-hand legend line */
764  for (j = 0; j < 256; j++) {
765  toprow[16 + 14][j] |= 0xFFFF;
766  }
767 
768  /* 14 rows with line on left to fill out this character row */
769  for (i = 13; i >= 0; i--) {
770  for (j = 0; j < 256; j++) {
771  toprow[16 + i][j] |= 0x0001;
772  }
773  }
774 
775  /* Form the longer tic marks in top legend */
776  for (i = 8; i < 16; i++) {
777  for (j = 0x0F; j < 0x100; j += 0x10) {
778  toprow[i][j] |= 0x0001;
779  }
780  }
781 
782  /*
783  Now write the raster image.
784 
785  XOR each byte with 0xFF because black = 0, white = 1 in BMP.
786  */
787 
788  /* Write the glyphs, bottom-up, left-to-right, in rows of 16 (i.e., 0x10) */
789  for (i = 0xFF00; i >= 0; i -= 0x100) {
790  thisrow = i >> 8; /* 256 glyphs per row */
791  for (j = 15; j >= 0; j--) {
792  /* left-hand legend */
793  putchar ((~leftcol[thisrow][j] >> 24) & 0xFF);
794  putchar ((~leftcol[thisrow][j] >> 16) & 0xFF);
795  putchar ((~leftcol[thisrow][j] >> 8) & 0xFF);
796  putchar ( ~leftcol[thisrow][j] & 0xFF);
797  /* Unifont glyph */
798  for (k = 0x00; k < 0x100; k++) {
799  bytesout = ~plane_array[i+k][j] & 0xFFFF;
800  putchar ((bytesout >> 8) & 0xFF);
801  putchar ( bytesout & 0xFF);
802  }
803  }
804  }
805 
806  /*
807  Write the top legend.
808  */
809  /* i == 15: bottom pixel row of header is output here */
810  /* left-hand legend: solid black line except for right-most pixel */
811  putchar (0x00);
812  putchar (0x00);
813  putchar (0x00);
814  putchar (0x01);
815  for (j = 0; j < 256; j++) {
816  putchar ((~toprow[16 + 15][j] >> 8) & 0xFF);
817  putchar ( ~toprow[16 + 15][j] & 0xFF);
818  }
819 
820  putchar (0xFF);
821  putchar (0xFF);
822  putchar (0xFF);
823  putchar (0xFC);
824  for (j = 0; j < 256; j++) {
825  putchar ((~toprow[16 + 14][j] >> 8) & 0xFF);
826  putchar ( ~toprow[16 + 14][j] & 0xFF);
827  }
828 
829  for (i = 16 + 13; i >= 0; i--) {
830  if (i >= 8) { /* make vertical stroke on right */
831  putchar (0xFF);
832  putchar (0xFF);
833  putchar (0xFF);
834  putchar (0xFD);
835  }
836  else { /* all white */
837  putchar (0xFF);
838  putchar (0xFF);
839  putchar (0xFF);
840  putchar (0xFF);
841  }
842  for (j = 0; j < 256; j++) {
843  putchar ((~toprow[i][j] >> 8) & 0xFF);
844  putchar ( ~toprow[i][j] & 0xFF);
845  }
846  }
847 
848  /*
849  Write the header.
850  */
851 
852  /* 8 completely white rows */
853  for (i = 7; i >= 0; i--) {
854  for (j = 0; j < 258; j++) {
855  putchar (0xFF);
856  putchar (0xFF);
857  }
858  }
859 
860  for (i = 15; i >= 0; i--) {
861  /* left-hand legend */
862  putchar (0xFF);
863  putchar (0xFF);
864  putchar (0xFF);
865  putchar (0xFF);
866  /* header glyph */
867  for (j = 0; j < 256; j++) {
868  bytesout = ~header[i][j] & 0xFFFF;
869  putchar ((bytesout >> 8) & 0xFF);
870  putchar ( bytesout & 0xFF);
871  }
872  }
873 
874  /* 8 completely white rows at very top */
875  for (i = 7; i >= 0; i--) {
876  for (j = 0; j < 258; j++) {
877  putchar (0xFF);
878  putchar (0xFF);
879  }
880  }
881 
882  return;
883 }
884 
unsigned hexdigit[16][4]
32 bit representation of 16x8 0..F bitmap
Definition: unibmp2hex.c:107
#define MAXSTRING
Definition: unifont1per.c:57
void gethex(char *instring, int plane_array[0x10000][16], int plane)
Read a Unifont .hex-format input file from stdin.
Definition: unifontpic.c:215
void genwidebmp(int plane_array[0x10000][16], int dpi, int tinynum, int plane)
Generate the BMP output file in wide format.
Definition: unifontpic.c:581
int main(int argc, char **argv)
The main function.
Definition: unifontpic.c:87
void output4(int thisword)
Output a 4-byte integer in little-endian order.
Definition: unifontpic.c:176
void output2(int thisword)
Output a 2-byte integer in little-endian order.
Definition: unifontpic.c:194
#define HDR_LEN
Definition: unifontpic.c:67
void genlongbmp(int plane_array[0x10000][16], int dpi, int tinynum, int plane)
Generate the BMP output file in long format.
Definition: unifontpic.c:294
unifontpic.h - Header file for unifontpic.c
#define HEADER_STRING
To be printed as chart title.
Definition: unifontpic.h:32
int ascii_bits[128][16]
Array to hold ASCII bitmaps for chart title.
Definition: unifontpic.h:179
const char * ascii_hex[128]
Array of Unifont ASCII glyphs for chart row & column headings.
Definition: unifontpic.h:42