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