GNU Unifont 15.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
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
hexdigit
unsigned hexdigit[16][4]
32 bit representation of 16x8 0..F bitmap
Definition: unibmp2hex.c:107
MAXSTRING
#define MAXSTRING
Definition: unifont1per.c:57
gethex
void gethex(char *instring, int plane_array[0x10000][16], int plane)
Read a Unifont .hex-format input file from stdin.
Definition: unifontpic.c:215
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:581
main
int main(int argc, char **argv)
The main function.
Definition: unifontpic.c:87
output4
void output4(int thisword)
Output a 4-byte integer in little-endian order.
Definition: unifontpic.c:176
output2
void output2(int thisword)
Output a 2-byte integer in little-endian order.
Definition: unifontpic.c:194
HDR_LEN
#define HDR_LEN
Definition: unifontpic.c:67
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:294
unifontpic.h
unifontpic.h - Header file for unifontpic.c
HEADER_STRING
#define HEADER_STRING
To be printed as chart title.
Definition: unifontpic.h:30
ascii_bits
int ascii_bits[128][16]
Array to hold ASCII bitmaps for chart title.
Definition: unifontpic.h:177
ascii_hex
const char * ascii_hex[128]
Array of Unifont ASCII glyphs for chart row & column headings.
Definition: unifontpic.h:40