GNU Unifont 17.0.01
Pan-Unicode font with complete Unicode Plane 0 coverage and partial coverage of higher planes
unibmp2hex.c
Go to the documentation of this file.
1/**
2 @file unibmp2hex.c
3
4 @brief unibmp2hex - Turn a .bmp or .wbmp glyph matrix into a
5 GNU Unifont hex glyph set of 256 characters
6
7 @author Paul Hardy, unifoundry <at> unifoundry.com, December 2007
8
9 @copyright Copyright (C) 2007, 2008, 2013, 2017, 2019, 2022 Paul Hardy
10
11 Synopsis: unibmp2hex [-iin_file.bmp] [-oout_file.hex] [-phex_page_num] [-w]
12*/
13/*
14
15 LICENSE:
16
17 This program is free software: you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation, either version 2 of the License, or
20 (at your option) any later version.
21
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with this program. If not, see <http://www.gnu.org/licenses/>.
29*/
30
31/*
32 20 June 2017 [Paul Hardy]:
33 - Modify to allow hard-coding of quadruple-width hex glyphs.
34 The 32nd column (rightmost column) is cleared to zero, because
35 that column contains the vertical cell border.
36 - Set U+9FD8..U+9FE9 (complex CJK) to be quadruple-width.
37 - Set U+011A00..U+011A4F (Masaram Gondi, non-digits) to be wide.
38 - Set U+011A50..U+011AAF (Soyombo) to be wide.
39
40 8 July 2017 [Paul Hardy]:
41 - All CJK glyphs in the range U+4E00..u+9FFF are double width
42 again; commented out the line that sets U+9FD8..U+9FE9 to be
43 quadruple width.
44
45 6 August 2017 [Paul Hardy]:
46 - Remove hard-coding of U+01D200..U+01D24F Ancient Greek Musical
47 Notation to double-width; allow range to be dual-width.
48
49 12 August 2017 [Paul Hardy]:
50 - Remove Miao script from list of wide scripts, so it can contain
51 single-width glyphs.
52
53 26 December 2017 Paul Hardy:
54 - Removed Tibetan from list of wide scripts, so it can contain
55 single-width glyphs.
56 - Added a number of scripts to be explicitly double-width in case
57 they are redrawn.
58 - Added Miao script back as wide, because combining glyphs are
59 added back to font/plane01/plane01-combining.txt.
60
61 05 June 2018 Paul Hardy:
62 - Made U+2329] and U+232A wide.
63 - Added to wide settings for CJK Compatibility Forms over entire range.
64 - Made Kayah Li script double-width.
65 - Made U+232A (Right-pointing Angle Bracket) double-width.
66 - Made U+01F5E7 (Three Rays Right) double-width.
67
68 July 2018 Paul Hardy:
69 - Changed 2017 to 2018 in previous change entry.
70 - Added Dogra (U+011800..U+01184F) as double width.
71 - Added Makasar (U+011EE0..U+011EFF) as dobule width.
72
73 23 February 2019 [Paul Hardy]:
74 - Set U+119A0..U+119FF (Nandinagari) to be wide.
75 - Set U+1E2C0..U+1E2FF (Wancho) to be wide.
76
77 25 May 2019 [Paul Hardy]:
78 - Added support for the case when the original .bmp monochrome
79 file has been converted to a 32 bit per pixel RGB file.
80 - Added support for bitmap images stored from either top to bottom
81 or bottom to top.
82 - Add DEBUG compile flag to print header information, to ease
83 adding support for additional bitmap formats in the future.
84
85 6 September 2021 [Paul Hardy]:
86 - Set U+12F90..U+12FFF (Cypro-Minoan) to be double width.
87 - Set U+1CF00..U+1CFCF (Znamenny Musical Notation) to be double width.
88 - Set U+1AFF0..U+1AFFF (Kana Extended-B) to be double width.
89
90 13 March 2022 [Paul Hardy]:
91 - Added support for 24 bits per pixel RGB file.
92
93 12 June 2022 [Paul Hardy]:
94 - Set U+11B00..U+11B5F (Devanagari Extended-A) to be wide.
95 - Set U+11F00..U+11F5F (Kawi) to be wide.
96
97 2 September 2024 [Paul Hardy] - Set these scripts to double width:
98 - U+10D40..U+10D8F (Garay)
99 - U+11380..U+113FF (Tulu-Tigalari)
100 - U+116D0..U+116FF (Myanmar Extended-C)
101 - U+11F00..U+11F5F (Kawi)
102 - U+16100..U+1613F (Gurung Khema)
103 - U+16D40..U+16D7F (Kirat Rai)
104 - U+18B00..U+18CFF (Khitan Small Script)
105 - U+1E5D0..U+1E5FF (Ol Onal)
106
107 19 April 2025 [Paul Hardy]:
108 - Remove hard-coding of U+1D100..U+1D1FF (Musical Symbols)
109 to double-width; allow range to be dual-width.
110
111 1 June 2025 [Paul Hardy]:
112 - Removed Wancho U+1E2C0..U+1E2FF) as a wide script; it is now
113 single-width.
114 - Added double-width block U+11B60..U+11B7F (Sharada Supplement).
115*/
116
117#include <stdio.h>
118#include <stdlib.h>
119#include <string.h>
120
121#define MAXBUF 256 ///< Maximum input file line length - 1
122
123
124unsigned hexdigit[16][4]; ///< 32 bit representation of 16x8 0..F bitmap
125
126unsigned uniplane=0; ///< Unicode plane number, 0..0xff ff ff
127unsigned planeset=0; ///< =1: use plane specified with -p parameter
128unsigned flip=0; ///< =1 if we're transposing glyph matrix
129unsigned forcewide=0; ///< =1 to set each glyph to 16 pixels wide
130
131/** The six Unicode plane digits, from left-most (0) to right-most (5) */
132unsigned unidigit[6][4];
133
134
135/** Bitmap Header parameters */
136struct {
137 char filetype[2];
138 int file_size;
139 int image_offset;
140 int info_size;
141 int width;
142 int height;
143 int nplanes;
144 int bits_per_pixel;
145 int compression;
146 int image_size;
147 int x_ppm;
148 int y_ppm;
149 int ncolors;
150 int important_colors;
152
153/** Bitmap Color Table -- maximum of 256 colors in a BMP file */
154unsigned char color_table[256][4]; /* R, G, B, alpha for up to 256 colors */
155
156// #define DEBUG
157
158/**
159 @brief The main function.
160
161 @param[in] argc The count of command line arguments.
162 @param[in] argv Pointer to array of command line arguments.
163 @return This program exits with status 0.
164*/
165int
166main (int argc, char *argv[])
167{
168
169 int i, j, k; /* loop variables */
170 unsigned char inchar; /* temporary input character */
171 char header[MAXBUF]; /* input buffer for bitmap file header */
172 int wbmp=0; /* =0 for Windows Bitmap (.bmp); 1 for Wireless Bitmap (.wbmp) */
173 int fatal; /* =1 if a fatal error occurred */
174 int match; /* =1 if we're still matching a pattern, 0 if no match */
175 int empty1, empty2; /* =1 if bytes tested are all zeroes */
176 unsigned char thischar1[16], thischar2[16]; /* bytes of hex char */
177 unsigned char thischar0[16], thischar3[16]; /* bytes for quadruple-width */
178 int thisrow; /* index to point into thischar1[] and thischar2[] */
179 int tmpsum; /* temporary sum to see if a character is blank */
180 unsigned this_pixel; /* color of one pixel, if > 1 bit per pixel */
181 unsigned next_pixels; /* pending group of 8 pixels being read */
182 unsigned color_mask = 0x00; /* to invert monochrome bitmap, set to 0xFF */
183
184 unsigned char bitmap[17*32][18*32/8]; /* final bitmap */
185 /* For wide array:
186 0 = don't force glyph to double-width;
187 1 = force glyph to double-width;
188 4 = force glyph to quadruple-width.
189 */
190 char wide[0x200000]={0x200000 * 0};
191
192 char *infile="", *outfile=""; /* names of input and output files */
193 FILE *infp, *outfp; /* file pointers of input and output files */
194
195 if (argc > 1) {
196 for (i = 1; i < argc; i++) {
197 if (argv[i][0] == '-') { /* this is an option argument */
198 switch (argv[i][1]) {
199 case 'i': /* name of input file */
200 infile = &argv[i][2];
201 break;
202 case 'o': /* name of output file */
203 outfile = &argv[i][2];
204 break;
205 case 'p': /* specify a Unicode plane */
206 sscanf (&argv[i][2], "%x", &uniplane); /* Get Unicode plane */
207 planeset = 1; /* Use specified range, not what's in bitmap */
208 break;
209 case 'w': /* force wide (16 pixels) for each glyph */
210 forcewide = 1;
211 break;
212 default: /* if unrecognized option, print list and exit */
213 fprintf (stderr, "\nSyntax:\n\n");
214 fprintf (stderr, " %s -p<Unicode_Page> ", argv[0]);
215 fprintf (stderr, "-i<Input_File> -o<Output_File> -w\n\n");
216 fprintf (stderr, " -w specifies .wbmp output instead of ");
217 fprintf (stderr, "default Windows .bmp output.\n\n");
218 fprintf (stderr, " -p is followed by 1 to 6 ");
219 fprintf (stderr, "Unicode plane hex digits ");
220 fprintf (stderr, "(default is Page 0).\n\n");
221 fprintf (stderr, "\nExample:\n\n");
222 fprintf (stderr, " %s -p83 -iunifont.hex -ou83.bmp\n\n\n",
223 argv[0]);
224 exit (1);
225 }
226 }
227 }
228 }
229 /*
230 Make sure we can open any I/O files that were specified before
231 doing anything else.
232 */
233 if (strlen (infile) > 0) {
234 if ((infp = fopen (infile, "r")) == NULL) {
235 fprintf (stderr, "Error: can't open %s for input.\n", infile);
236 exit (1);
237 }
238 }
239 else {
240 infp = stdin;
241 }
242 if (strlen (outfile) > 0) {
243 if ((outfp = fopen (outfile, "w")) == NULL) {
244 fprintf (stderr, "Error: can't open %s for output.\n", outfile);
245 exit (1);
246 }
247 }
248 else {
249 outfp = stdout;
250 }
251 /*
252 Initialize selected code points for double width (16x16).
253 Double-width is forced in cases where a glyph (usually a combining
254 glyph) only occupies the left-hand side of a 16x16 grid, but must
255 be rendered as double-width to appear properly with other glyphs
256 in a given script. If additions were made to a script after
257 Unicode 5.0, the Unicode version is given in parentheses after
258 the script name.
259 */
260 for (i = 0x0700; i <= 0x074F; i++) wide[i] = 1; /* Syriac */
261 for (i = 0x0800; i <= 0x083F; i++) wide[i] = 1; /* Samaritan (5.2) */
262 for (i = 0x0900; i <= 0x0DFF; i++) wide[i] = 1; /* Indic */
263 for (i = 0x1000; i <= 0x109F; i++) wide[i] = 1; /* Myanmar */
264 for (i = 0x1100; i <= 0x11FF; i++) wide[i] = 1; /* Hangul Jamo */
265 for (i = 0x1400; i <= 0x167F; i++) wide[i] = 1; /* Canadian Aboriginal */
266 for (i = 0x1700; i <= 0x171F; i++) wide[i] = 1; /* Tagalog */
267 for (i = 0x1720; i <= 0x173F; i++) wide[i] = 1; /* Hanunoo */
268 for (i = 0x1740; i <= 0x175F; i++) wide[i] = 1; /* Buhid */
269 for (i = 0x1760; i <= 0x177F; i++) wide[i] = 1; /* Tagbanwa */
270 for (i = 0x1780; i <= 0x17FF; i++) wide[i] = 1; /* Khmer */
271 for (i = 0x18B0; i <= 0x18FF; i++) wide[i] = 1; /* Ext. Can. Aboriginal */
272 for (i = 0x1800; i <= 0x18AF; i++) wide[i] = 1; /* Mongolian */
273 for (i = 0x1900; i <= 0x194F; i++) wide[i] = 1; /* Limbu */
274// for (i = 0x1980; i <= 0x19DF; i++) wide[i] = 1; /* New Tai Lue */
275 for (i = 0x1A00; i <= 0x1A1F; i++) wide[i] = 1; /* Buginese */
276 for (i = 0x1A20; i <= 0x1AAF; i++) wide[i] = 1; /* Tai Tham (5.2) */
277 for (i = 0x1B00; i <= 0x1B7F; i++) wide[i] = 1; /* Balinese */
278 for (i = 0x1B80; i <= 0x1BBF; i++) wide[i] = 1; /* Sundanese (5.1) */
279 for (i = 0x1BC0; i <= 0x1BFF; i++) wide[i] = 1; /* Batak (6.0) */
280 for (i = 0x1C00; i <= 0x1C4F; i++) wide[i] = 1; /* Lepcha (5.1) */
281 for (i = 0x1CC0; i <= 0x1CCF; i++) wide[i] = 1; /* Sundanese Supplement */
282 for (i = 0x1CD0; i <= 0x1CFF; i++) wide[i] = 1; /* Vedic Extensions (5.2) */
283 wide[0x2329] = wide[0x232A] = 1; /* Left- & Right-pointing Angle Brackets */
284 for (i = 0x2E80; i <= 0xA4CF; i++) wide[i] = 1; /* CJK */
285// for (i = 0x9FD8; i <= 0x9FE9; i++) wide[i] = 4; /* CJK quadruple-width */
286 for (i = 0xA900; i <= 0xA92F; i++) wide[i] = 1; /* Kayah Li (5.1) */
287 for (i = 0xA930; i <= 0xA95F; i++) wide[i] = 1; /* Rejang (5.1) */
288 for (i = 0xA960; i <= 0xA97F; i++) wide[i] = 1; /* Hangul Jamo Extended-A */
289 for (i = 0xA980; i <= 0xA9DF; i++) wide[i] = 1; /* Javanese (5.2) */
290 for (i = 0xAA00; i <= 0xAA5F; i++) wide[i] = 1; /* Cham (5.1) */
291 for (i = 0xA9E0; i <= 0xA9FF; i++) wide[i] = 1; /* Myanmar Extended-B */
292 for (i = 0xAA00; i <= 0xAA5F; i++) wide[i] = 1; /* Cham */
293 for (i = 0xAA60; i <= 0xAA7F; i++) wide[i] = 1; /* Myanmar Extended-A */
294 for (i = 0xAAE0; i <= 0xAAFF; i++) wide[i] = 1; /* Meetei Mayek Ext (6.0) */
295 for (i = 0xABC0; i <= 0xABFF; i++) wide[i] = 1; /* Meetei Mayek (5.2) */
296 for (i = 0xAC00; i <= 0xD7AF; i++) wide[i] = 1; /* Hangul Syllables */
297 for (i = 0xD7B0; i <= 0xD7FF; i++) wide[i] = 1; /* Hangul Jamo Extended-B */
298 for (i = 0xF900; i <= 0xFAFF; i++) wide[i] = 1; /* CJK Compatibility */
299 for (i = 0xFE10; i <= 0xFE1F; i++) wide[i] = 1; /* Vertical Forms */
300 for (i = 0xFE30; i <= 0xFE60; i++) wide[i] = 1; /* CJK Compatibility Forms*/
301 for (i = 0xFFE0; i <= 0xFFE6; i++) wide[i] = 1; /* CJK Compatibility Forms*/
302
303 wide[0x303F] = 0; /* CJK half-space fill */
304
305 /* Supplemental Multilingual Plane (Plane 01) */
306 for (i = 0x0105C0; i <= 0x0105FF; i++) wide[i] = 1; /* Todhri */
307 for (i = 0x010A00; i <= 0x010A5F; i++) wide[i] = 1; /* Kharoshthi */
308 for (i = 0x011000; i <= 0x01107F; i++) wide[i] = 1; /* Brahmi */
309 for (i = 0x011080; i <= 0x0110CF; i++) wide[i] = 1; /* Kaithi */
310 for (i = 0x011100; i <= 0x01114F; i++) wide[i] = 1; /* Chakma */
311 for (i = 0x011180; i <= 0x0111DF; i++) wide[i] = 1; /* Sharada */
312 for (i = 0x011200; i <= 0x01124F; i++) wide[i] = 1; /* Khojki */
313 for (i = 0x0112B0; i <= 0x0112FF; i++) wide[i] = 1; /* Khudawadi */
314 for (i = 0x011300; i <= 0x01137F; i++) wide[i] = 1; /* Grantha */
315 for (i = 0x011380; i <= 0x0113FF; i++) wide[i] = 1; /* Tulu-Tigalari */
316 for (i = 0x011400; i <= 0x01147F; i++) wide[i] = 1; /* Newa */
317 for (i = 0x011480; i <= 0x0114DF; i++) wide[i] = 1; /* Tirhuta */
318 for (i = 0x011580; i <= 0x0115FF; i++) wide[i] = 1; /* Siddham */
319 for (i = 0x011600; i <= 0x01165F; i++) wide[i] = 1; /* Modi */
320 for (i = 0x011660; i <= 0x01167F; i++) wide[i] = 1; /* Mongolian Suppl. */
321 for (i = 0x011680; i <= 0x0116CF; i++) wide[i] = 1; /* Takri */
322 for (i = 0x0116D0; i <= 0x0116FF; i++) wide[i] = 1; /* Myanmar Extended-C */
323 for (i = 0x011700; i <= 0x01173F; i++) wide[i] = 1; /* Ahom */
324 for (i = 0x011800; i <= 0x01184F; i++) wide[i] = 1; /* Dogra */
325 for (i = 0x011900; i <= 0x01195F; i++) wide[i] = 1; /* Dives Akuru */
326 for (i = 0x0119A0; i <= 0x0119FF; i++) wide[i] = 1; /* Nandinagari */
327 for (i = 0x011A00; i <= 0x011A4F; i++) wide[i] = 1; /* Zanabazar Square */
328 for (i = 0x011A50; i <= 0x011AAF; i++) wide[i] = 1; /* Soyombo */
329 for (i = 0x011B00; i <= 0x011B5F; i++) wide[i] = 1;/*Devanagari Extended-A*/
330 for (i = 0x011B60; i <= 0x011B7F; i++) wide[i] = 1; /* Sharada Supplement */
331 for (i = 0x011F00; i <= 0x011F5F; i++) wide[i] = 1; /* Kawi */
332 for (i = 0x011C00; i <= 0x011C6F; i++) wide[i] = 1; /* Bhaiksuki */
333 for (i = 0x011C70; i <= 0x011CBF; i++) wide[i] = 1; /* Marchen */
334 for (i = 0x011D00; i <= 0x011D5F; i++) wide[i] = 1; /* Masaram Gondi */
335 for (i = 0x011EE0; i <= 0x011EFF; i++) wide[i] = 1; /* Makasar */
336 for (i = 0x011F00; i <= 0x011F5F; i++) wide[i] = 1; /* Kawi */
337 for (i = 0x012F90; i <= 0x012FFF; i++) wide[i] = 1; /* Cypro-Minoan */
338 /* Make Bassa Vah all single width or all double width */
339 for (i = 0x016100; i <= 0x01613F; i++) wide[i] = 1; /* Gurung Khema */
340 for (i = 0x016AD0; i <= 0x016AFF; i++) wide[i] = 1; /* Bassa Vah */
341 for (i = 0x016B00; i <= 0x016B8F; i++) wide[i] = 1; /* Pahawh Hmong */
342 for (i = 0x016D40; i <= 0x016D7F; i++) wide[i] = 1; /* Kirat Rai */
343 for (i = 0x016F00; i <= 0x016F9F; i++) wide[i] = 1; /* Miao */
344 for (i = 0x016FE0; i <= 0x016FFF; i++) wide[i] = 1; /* Ideograph Sym/Punct*/
345 for (i = 0x017000; i <= 0x0187FF; i++) wide[i] = 1; /* Tangut */
346 for (i = 0x018800; i <= 0x018AFF; i++) wide[i] = 1; /* Tangut Components */
347 for (i = 0x018B00; i <= 0x018CFF; i++) wide[i] = 1; /* Khitan Small Script*/
348 for (i = 0x01AFF0; i <= 0x01AFFF; i++) wide[i] = 1; /* Kana Extended-B */
349 for (i = 0x01B000; i <= 0x01B0FF; i++) wide[i] = 1; /* Kana Supplement */
350 for (i = 0x01B100; i <= 0x01B12F; i++) wide[i] = 1; /* Kana Extended-A */
351 for (i = 0x01B170; i <= 0x01B2FF; i++) wide[i] = 1; /* Nushu */
352 for (i = 0x01CF00; i <= 0x01CFCF; i++) wide[i] = 1; /* Znamenny Musical */
353 for (i = 0x01D800; i <= 0x01DAAF; i++) wide[i] = 1; /* Sutton SignWriting */
354 for (i = 0x01E500; i <= 0x01E5FF; i++) wide[i] = 1; /* Ol Onal */
355 for (i = 0x01E800; i <= 0x01E8DF; i++) wide[i] = 1; /* Mende Kikakui */
356 for (i = 0x01F200; i <= 0x01F2FF; i++) wide[i] = 1; /* Encl Ideograp Suppl*/
357 wide[0x01F5E7] = 1; /* Three Rays Right */
358
359 /*
360 Determine whether or not the file is a Microsoft Windows Bitmap file.
361 If it starts with 'B', 'M', assume it's a Windows Bitmap file.
362 Otherwise, assume it's a Wireless Bitmap file.
363
364 WARNING: There isn't much in the way of error checking here --
365 if you give it a file that wasn't first created by hex2bmp.c,
366 all bets are off.
367 */
368 fatal = 0; /* assume everything is okay with reading input file */
369 if ((header[0] = fgetc (infp)) != EOF) {
370 if ((header[1] = fgetc (infp)) != EOF) {
371 if (header[0] == 'B' && header[1] == 'M') {
372 wbmp = 0; /* Not a Wireless Bitmap -- it's a Windows Bitmap */
373 }
374 else {
375 wbmp = 1; /* Assume it's a Wireless Bitmap */
376 }
377 }
378 else
379 fatal = 1;
380 }
381 else
382 fatal = 1;
383
384 if (fatal) {
385 fprintf (stderr, "Fatal error; end of input file.\n\n");
386 exit (1);
387 }
388 /*
389 If this is a Wireless Bitmap (.wbmp) format file,
390 skip the header and point to the start of the bitmap itself.
391 */
392 if (wbmp) {
393 for (i=2; i<6; i++)
394 header[i] = fgetc (infp);
395 /*
396 Now read the bitmap.
397 */
398 for (i=0; i < 32*17; i++) {
399 for (j=0; j < 32*18/8; j++) {
400 inchar = fgetc (infp);
401 bitmap[i][j] = ~inchar; /* invert bits for proper color */
402 }
403 }
404 }
405 /*
406 Otherwise, treat this as a Windows Bitmap file, because we checked
407 that it began with "BM". Save the header contents for future use.
408 Expect a 14 byte standard BITMAPFILEHEADER format header followed
409 by a 40 byte standard BITMAPINFOHEADER Device Independent Bitmap
410 header, with data stored in little-endian format.
411 */
412 else {
413 for (i = 2; i < 54; i++)
414 header[i] = fgetc (infp);
415
416 bmp_header.filetype[0] = 'B';
417 bmp_header.filetype[1] = 'M';
418
419 bmp_header.file_size =
420 (header[2] & 0xFF) | ((header[3] & 0xFF) << 8) |
421 ((header[4] & 0xFF) << 16) | ((header[5] & 0xFF) << 24);
422
423 /* header bytes 6..9 are reserved */
424
425 bmp_header.image_offset =
426 (header[10] & 0xFF) | ((header[11] & 0xFF) << 8) |
427 ((header[12] & 0xFF) << 16) | ((header[13] & 0xFF) << 24);
428
429 bmp_header.info_size =
430 (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) |
431 ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24);
432
433 bmp_header.width =
434 (header[18] & 0xFF) | ((header[19] & 0xFF) << 8) |
435 ((header[20] & 0xFF) << 16) | ((header[21] & 0xFF) << 24);
436
437 bmp_header.height =
438 (header[22] & 0xFF) | ((header[23] & 0xFF) << 8) |
439 ((header[24] & 0xFF) << 16) | ((header[25] & 0xFF) << 24);
440
441 bmp_header.nplanes =
442 (header[26] & 0xFF) | ((header[27] & 0xFF) << 8);
443
444 bmp_header.bits_per_pixel =
445 (header[28] & 0xFF) | ((header[29] & 0xFF) << 8);
446
447 bmp_header.compression =
448 (header[30] & 0xFF) | ((header[31] & 0xFF) << 8) |
449 ((header[32] & 0xFF) << 16) | ((header[33] & 0xFF) << 24);
450
451 bmp_header.image_size =
452 (header[34] & 0xFF) | ((header[35] & 0xFF) << 8) |
453 ((header[36] & 0xFF) << 16) | ((header[37] & 0xFF) << 24);
454
455 bmp_header.x_ppm =
456 (header[38] & 0xFF) | ((header[39] & 0xFF) << 8) |
457 ((header[40] & 0xFF) << 16) | ((header[41] & 0xFF) << 24);
458
459 bmp_header.y_ppm =
460 (header[42] & 0xFF) | ((header[43] & 0xFF) << 8) |
461 ((header[44] & 0xFF) << 16) | ((header[45] & 0xFF) << 24);
462
463 bmp_header.ncolors =
464 (header[46] & 0xFF) | ((header[47] & 0xFF) << 8) |
465 ((header[48] & 0xFF) << 16) | ((header[49] & 0xFF) << 24);
466
467 bmp_header.important_colors =
468 (header[50] & 0xFF) | ((header[51] & 0xFF) << 8) |
469 ((header[52] & 0xFF) << 16) | ((header[53] & 0xFF) << 24);
470
471 if (bmp_header.ncolors == 0)
472 bmp_header.ncolors = 1 << bmp_header.bits_per_pixel;
473
474 /* If a Color Table exists, read it */
475 if (bmp_header.ncolors > 0 && bmp_header.bits_per_pixel <= 8) {
476 for (i = 0; i < bmp_header.ncolors; i++) {
477 color_table[i][0] = fgetc (infp); /* Red */
478 color_table[i][1] = fgetc (infp); /* Green */
479 color_table[i][2] = fgetc (infp); /* Blue */
480 color_table[i][3] = fgetc (infp); /* Alpha */
481 }
482 /*
483 Determine from the first color table entry whether we
484 are inverting the resulting bitmap image.
485 */
486 if ( (color_table[0][0] + color_table[0][1] + color_table[0][2])
487 < (3 * 128) ) {
488 color_mask = 0xFF;
489 }
490 }
491
492#ifdef DEBUG
493
494 /*
495 Print header info for possibly adding support for
496 additional file formats in the future, to determine
497 how the bitmap is encoded.
498 */
499 fprintf (stderr, "Filetype: '%c%c'\n",
500 bmp_header.filetype[0], bmp_header.filetype[1]);
501 fprintf (stderr, "File Size: %d\n", bmp_header.file_size);
502 fprintf (stderr, "Image Offset: %d\n", bmp_header.image_offset);
503 fprintf (stderr, "Info Header Size: %d\n", bmp_header.info_size);
504 fprintf (stderr, "Image Width: %d\n", bmp_header.width);
505 fprintf (stderr, "Image Height: %d\n", bmp_header.height);
506 fprintf (stderr, "Number of Planes: %d\n", bmp_header.nplanes);
507 fprintf (stderr, "Bits per Pixel: %d\n", bmp_header.bits_per_pixel);
508 fprintf (stderr, "Compression Method: %d\n", bmp_header.compression);
509 fprintf (stderr, "Image Size: %d\n", bmp_header.image_size);
510 fprintf (stderr, "X Pixels per Meter: %d\n", bmp_header.x_ppm);
511 fprintf (stderr, "Y Pixels per Meter: %d\n", bmp_header.y_ppm);
512 fprintf (stderr, "Number of Colors: %d\n", bmp_header.ncolors);
513 fprintf (stderr, "Important Colors: %d\n", bmp_header.important_colors);
514
515#endif
516
517 /*
518 Now read the bitmap.
519 */
520 for (i = 32*17-1; i >= 0; i--) {
521 for (j=0; j < 32*18/8; j++) {
522 next_pixels = 0x00; /* initialize next group of 8 pixels */
523 /* Read a monochrome image -- the original case */
524 if (bmp_header.bits_per_pixel == 1) {
525 next_pixels = fgetc (infp);
526 }
527 /* Read a 32 bit per pixel RGB image; convert to monochrome */
528 else if ( bmp_header.bits_per_pixel == 24 ||
529 bmp_header.bits_per_pixel == 32) {
530 next_pixels = 0;
531 for (k = 0; k < 8; k++) { /* get next 8 pixels */
532 this_pixel = (fgetc (infp) & 0xFF) +
533 (fgetc (infp) & 0xFF) +
534 (fgetc (infp) & 0xFF);
535
536 if (bmp_header.bits_per_pixel == 32) {
537 (void) fgetc (infp); /* ignore alpha value */
538 }
539
540 /* convert RGB color space to monochrome */
541 if (this_pixel >= (128 * 3))
542 this_pixel = 0;
543 else
544 this_pixel = 1;
545
546 /* shift next pixel color into place for 8 pixels total */
547 next_pixels = (next_pixels << 1) | this_pixel;
548 }
549 }
550 if (bmp_header.height < 0) { /* Bitmap drawn top to bottom */
551 bitmap [(32*17-1) - i] [j] = next_pixels;
552 }
553 else { /* Bitmap drawn bottom to top */
554 bitmap [i][j] = next_pixels;
555 }
556 }
557 }
558
559 /*
560 If any bits are set in color_mask, apply it to
561 entire bitmap to invert black <--> white.
562 */
563 if (color_mask != 0x00) {
564 for (i = 32*17-1; i >= 0; i--) {
565 for (j=0; j < 32*18/8; j++) {
566 bitmap [i][j] ^= color_mask;
567 }
568 }
569 }
570
571 }
572
573 /*
574 We've read the entire file. Now close the input file pointer.
575 */
576 fclose (infp);
577 /*
578 We now have the header portion in the header[] array,
579 and have the bitmap portion from top-to-bottom in the bitmap[] array.
580 */
581 /*
582 If no Unicode range (U+nnnnnn00 through U+nnnnnnFF) was specified
583 with a -p parameter, determine the range from the digits in the
584 bitmap itself.
585
586 Store bitmaps for the hex digit patterns that this file uses.
587 */
588 if (!planeset) { /* If Unicode range not specified with -p parameter */
589 for (i = 0x0; i <= 0xF; i++) { /* hex digit pattern we're storing */
590 for (j = 0; j < 4; j++) {
591 hexdigit[i][j] =
592 ((unsigned)bitmap[32 * (i+1) + 4 * j + 8 ][6] << 24 ) |
593 ((unsigned)bitmap[32 * (i+1) + 4 * j + 8 + 1][6] << 16 ) |
594 ((unsigned)bitmap[32 * (i+1) + 4 * j + 8 + 2][6] << 8 ) |
595 ((unsigned)bitmap[32 * (i+1) + 4 * j + 8 + 3][6] );
596 }
597 }
598 /*
599 Read the Unicode plane digits into arrays for comparison, to
600 determine the upper four hex digits of the glyph addresses.
601 */
602 for (i = 0; i < 4; i++) {
603 for (j = 0; j < 4; j++) {
604 unidigit[i][j] =
605 ((unsigned)bitmap[32 * 0 + 4 * j + 8 + 1][i + 3] << 24 ) |
606 ((unsigned)bitmap[32 * 0 + 4 * j + 8 + 2][i + 3] << 16 ) |
607 ((unsigned)bitmap[32 * 0 + 4 * j + 8 + 3][i + 3] << 8 ) |
608 ((unsigned)bitmap[32 * 0 + 4 * j + 8 + 4][i + 3] );
609 }
610 }
611
612 tmpsum = 0;
613 for (i = 4; i < 6; i++) {
614 for (j = 0; j < 4; j++) {
615 unidigit[i][j] =
616 ((unsigned)bitmap[32 * 1 + 4 * j + 8 ][i] << 24 ) |
617 ((unsigned)bitmap[32 * 1 + 4 * j + 8 + 1][i] << 16 ) |
618 ((unsigned)bitmap[32 * 1 + 4 * j + 8 + 2][i] << 8 ) |
619 ((unsigned)bitmap[32 * 1 + 4 * j + 8 + 3][i] );
620 tmpsum |= unidigit[i][j];
621 }
622 }
623 if (tmpsum == 0) { /* the glyph matrix is transposed */
624 flip = 1; /* note transposed order for processing glyphs in matrix */
625 /*
626 Get 5th and 6th hex digits by shifting first column header left by
627 1.5 columns, thereby shifting the hex digit right after the leading
628 "U+nnnn" page number.
629 */
630 for (i = 0x08; i < 0x18; i++) {
631 bitmap[i][7] = (bitmap[i][8] << 4) | ((bitmap[i][ 9] >> 4) & 0xf);
632 bitmap[i][8] = (bitmap[i][9] << 4) | ((bitmap[i][10] >> 4) & 0xf);
633 }
634 for (i = 4; i < 6; i++) {
635 for (j = 0; j < 4; j++) {
636 unidigit[i][j] =
637 ((unsigned)bitmap[4 * j + 8 + 1][i + 3] << 24 ) |
638 ((unsigned)bitmap[4 * j + 8 + 2][i + 3] << 16 ) |
639 ((unsigned)bitmap[4 * j + 8 + 3][i + 3] << 8 ) |
640 ((unsigned)bitmap[4 * j + 8 + 4][i + 3] );
641 }
642 }
643 }
644
645 /*
646 Now determine the Unicode plane by comparing unidigit[0..5] to
647 the hexdigit[0x0..0xF] array.
648 */
649 uniplane = 0;
650 for (i=0; i<6; i++) { /* go through one bitmap digit at a time */
651 match = 0; /* haven't found pattern yet */
652 for (j = 0x0; !match && j <= 0xF; j++) {
653 if (unidigit[i][0] == hexdigit[j][0] &&
654 unidigit[i][1] == hexdigit[j][1] &&
655 unidigit[i][2] == hexdigit[j][2] &&
656 unidigit[i][3] == hexdigit[j][3]) { /* we found the digit */
657 uniplane |= j;
658 match = 1;
659 }
660 }
661 uniplane <<= 4;
662 }
663 uniplane >>= 4;
664 }
665 /*
666 Now read each glyph and print it as hex.
667 */
668 for (i = 0x0; i <= 0xf; i++) {
669 for (j = 0x0; j <= 0xf; j++) {
670 for (k = 0; k < 16; k++) {
671 if (flip) { /* transpose glyph matrix */
672 thischar0[k] = bitmap[32*(j+1) + k + 7][4 * (i+2) ];
673 thischar1[k] = bitmap[32*(j+1) + k + 7][4 * (i+2) + 1];
674 thischar2[k] = bitmap[32*(j+1) + k + 7][4 * (i+2) + 2];
675 thischar3[k] = bitmap[32*(j+1) + k + 7][4 * (i+2) + 3];
676 }
677 else {
678 thischar0[k] = bitmap[32*(i+1) + k + 7][4 * (j+2) ];
679 thischar1[k] = bitmap[32*(i+1) + k + 7][4 * (j+2) + 1];
680 thischar2[k] = bitmap[32*(i+1) + k + 7][4 * (j+2) + 2];
681 thischar3[k] = bitmap[32*(i+1) + k + 7][4 * (j+2) + 3];
682 }
683 }
684 /*
685 If the second half of the 16*16 character is all zeroes, this
686 character is only 8 bits wide, so print a half-width character.
687 */
688 empty1 = empty2 = 1;
689 for (k=0; (empty1 || empty2) && k < 16; k++) {
690 if (thischar1[k] != 0) empty1 = 0;
691 if (thischar2[k] != 0) empty2 = 0;
692 }
693 /*
694 Only print this glyph if it isn't blank.
695 */
696 if (!empty1 || !empty2) {
697 /*
698 If the second half is empty, this is a half-width character.
699 Only print the first half.
700 */
701 /*
702 Original GNU Unifont format is four hexadecimal digit character
703 code followed by a colon followed by a hex string. Add support
704 for codes beyond the Basic Multilingual Plane.
705
706 Unicode ranges from U+0000 to U+10FFFF, so print either a
707 4-digit or a 6-digit code point. Note that this software
708 should support up to an 8-digit code point, extending beyond
709 the normal Unicode range, but this has not been fully tested.
710 */
711 if (uniplane > 0xff)
712 fprintf (outfp, "%04X%X%X:", uniplane, i, j); // 6 digit code pt.
713 else
714 fprintf (outfp, "%02X%X%X:", uniplane, i, j); // 4 digit code pt.
715 for (thisrow=0; thisrow<16; thisrow++) {
716 /*
717 If second half is empty and we're not forcing this
718 code point to double width, print as single width.
719 */
720 if (!forcewide &&
721 empty2 && !wide[(uniplane << 8) | (i << 4) | j]) {
722 fprintf (outfp,
723 "%02X",
724 thischar1[thisrow]);
725 }
726 else if (wide[(uniplane << 8) | (i << 4) | j] == 4) {
727 /* quadruple-width; force 32nd pixel to zero */
728 fprintf (outfp,
729 "%02X%02X%02X%02X",
730 thischar0[thisrow], thischar1[thisrow],
731 thischar2[thisrow], thischar3[thisrow] & 0xFE);
732 }
733 else { /* treat as double-width */
734 fprintf (outfp,
735 "%02X%02X",
736 thischar1[thisrow], thischar2[thisrow]);
737 }
738 }
739 fprintf (outfp, "\n");
740 }
741 }
742 }
743 exit (0);
744}
int main(void)
The main function.
Definition: unibdf2hex.c:46
unsigned planeset
=1: use plane specified with -p parameter
Definition: unibmp2hex.c:127
unsigned unidigit[6][4]
Definition: unibmp2hex.c:132
unsigned uniplane
Unicode plane number, 0..0xff ff ff.
Definition: unibmp2hex.c:126
unsigned forcewide
=1 to set each glyph to 16 pixels wide
Definition: unibmp2hex.c:129
struct @0 bmp_header
unsigned hexdigit[16][4]
32 bit representation of 16x8 0..F bitmap
Definition: unibmp2hex.c:124
unsigned char color_table[256][4]
Definition: unibmp2hex.c:154
#define MAXBUF
Maximum input file line length - 1.
Definition: unibmp2hex.c:121
unsigned flip
=1 if we're transposing glyph matrix
Definition: unibmp2hex.c:128