GNU Unifont: src/unifontpic.c Source File

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