GNU Unifont  15.0.05
Pan-Unicode font with complete Unicode Plane 0 coverage and partial coverage of higher planes
unibmpbump.c File Reference

unibmpbump - Adjust a Microsoft bitmap (.bmp) file that was created by unihex2png but converted to .bmp More...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Include dependency graph for unibmpbump.c:

Go to the source code of this file.

Macros

#define VERSION   "1.0"
 Version of this program.
 
#define MAX_COMPRESSION_METHOD   13
 Maximum supported compression method.
 

Functions

int main (int argc, char *argv[])
 The main function. More...
 
unsigned get_bytes (FILE *infp, int nbytes)
 Get from 1 to 4 bytes, inclusive, from input file. More...
 
void regrid (unsigned *image_bytes)
 After reading in the image, shift it. More...
 

Detailed Description

unibmpbump - Adjust a Microsoft bitmap (.bmp) file that was created by unihex2png but converted to .bmp

Author
Paul Hardy, unifoundry <at> unifoundry.com

This program shifts the glyphs in a bitmap file to adjust an original PNG file that was saved in BMP format. This is so the result matches the format of a unihex2bmp image. This conversion then lets unibmp2hex decode the result.

Synopsis: unibmpbump [-iin_file.bmp] [-oout_file.bmp]

Definition in file unibmpbump.c.

Function Documentation

◆ get_bytes()

unsigned get_bytes ( FILE *  infp,
int  nbytes 
)

Get from 1 to 4 bytes, inclusive, from input file.

Parameters
[in]infpPointer to input file.
[in]nbytesNumber of bytes to read, from 1 to 4, inclusive.
Returns
The unsigned 1 to 4 bytes in machine native endian format.

Definition at line 487 of file unibmpbump.c.

487  {
488  int i;
489  unsigned char inchar[4];
490  unsigned inword;
491 
492  for (i = 0; i < nbytes; i++) {
493  if (fread (&inchar[i], 1, 1, infp) != 1) {
494  inchar[i] = 0;
495  }
496  }
497  for (i = nbytes; i < 4; i++) inchar[i] = 0;
498 
499  inword = ((inchar[3] & 0xFF) << 24) | ((inchar[2] & 0xFF) << 16) |
500  ((inchar[1] & 0xFF) << 8) | (inchar[0] & 0xFF);
501 
502  return inword;
503 }

◆ main()

int main ( int  argc,
char *  argv[] 
)

The main function.

Parameters
[in]argcThe count of command line arguments.
[in]argvPointer to array of command line arguments.
Returns
This program exits with status EXIT_SUCCESS.

Definition at line 50 of file unibmpbump.c.

50  {
51 
52  /*
53  Values preserved from file header (first 14 bytes).
54  */
55  char file_format[3]; /* "BM" for original Windows format */
56  unsigned filesize; /* size of file in bytes */
57  unsigned char rsvd_hdr[4]; /* 4 reserved bytes */
58  unsigned image_start; /* byte offset of image in file */
59 
60  /*
61  Values preserved from Device Independent Bitmap (DIB) Header.
62 
63  The DIB fields below are in the standard 40-byte header. Version
64  4 and version 5 headers have more information, mainly for color
65  information. That is skipped over, because a valid glyph image
66  is just monochrome.
67  */
68  int dib_length; /* in bytes, for parsing by header version */
69  int image_width = 0; /* Signed image width */
70  int image_height = 0; /* Signed image height */
71  int num_planes = 0; /* number of planes; must be 1 */
72  int bits_per_pixel = 0; /* for palletized color maps (< 2^16 colors) */
73  /*
74  The following fields are not in the original spec, so initialize
75  them to 0 so we can correctly parse an original file format.
76  */
77  int compression_method=0; /* 0 --> uncompressed RGB/monochrome */
78  int image_size = 0; /* 0 is a valid size if no compression */
79  int hres = 0; /* image horizontal resolution */
80  int vres = 0; /* image vertical resolution */
81  int num_colors = 0; /* Number of colors for pallettized images */
82  int important_colors = 0; /* Number of significant colors (0 or 2) */
83 
84  int true_colors = 0; /* interpret num_colors, which can equal 0 */
85 
86  /*
87  Color map. This should be a monochrome file, so only two
88  colors are stored.
89  */
90  unsigned char color_map[2][4]; /* two of R, G, B, and possibly alpha */
91 
92  /*
93  The monochrome image bitmap, stored as a vector 544 rows by
94  72*8 columns.
95  */
96  unsigned image_bytes[544*72];
97 
98  /*
99  Flags for conversion & I/O.
100  */
101  int verbose = 0; /* Whether to print file info on stderr */
102  unsigned image_xor = 0x00; /* Invert (= 0xFF) if color 0 is not black */
103 
104  /*
105  Temporary variables.
106  */
107  int i, j, k; /* loop variables */
108 
109  /* Compression type, for parsing file */
110  char *compression_type[MAX_COMPRESSION_METHOD + 1] = {
111  "BI_RGB", /* 0 */
112  "BI_RLE8", /* 1 */
113  "BI_RLE4", /* 2 */
114  "BI_BITFIELDS", /* 3 */
115  "BI_JPEG", /* 4 */
116  "BI_PNG", /* 5 */
117  "BI_ALPHABITFIELDS", /* 6 */
118  "", "", "", "", /* 7 - 10 */
119  "BI_CMYK", /* 11 */
120  "BI_CMYKRLE8", /* 12 */
121  "BI_CMYKRLE4", /* 13 */
122  };
123 
124  /* Standard unihex2bmp.c header for BMP image */
125  unsigned standard_header [62] = {
126  /* 0 */ 0x42, 0x4d, 0x3e, 0x99, 0x00, 0x00, 0x00, 0x00,
127  /* 8 */ 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x28, 0x00,
128  /* 16 */ 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x20, 0x02,
129  /* 24 */ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
130  /* 32 */ 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0xc4, 0x0e,
131  /* 40 */ 0x00, 0x00, 0xc4, 0x0e, 0x00, 0x00, 0x00, 0x00,
132  /* 48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133  /* 56 */ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00
134  };
135 
136  unsigned get_bytes (FILE *, int);
137  void regrid (unsigned *);
138 
139  char *infile="", *outfile=""; /* names of input and output files */
140  FILE *infp, *outfp; /* file pointers of input and output files */
141 
142  /*
143  Process command line arguments.
144  */
145  if (argc > 1) {
146  for (i = 1; i < argc; i++) {
147  if (argv[i][0] == '-') { /* this is an option argument */
148  switch (argv[i][1]) {
149  case 'i': /* name of input file */
150  infile = &argv[i][2];
151  break;
152  case 'o': /* name of output file */
153  outfile = &argv[i][2];
154  break;
155  case 'v': /* verbose output */
156  verbose = 1;
157  break;
158  case 'V': /* print version & quit */
159  fprintf (stderr, "unibmpbump version %s\n\n", VERSION);
160  exit (EXIT_SUCCESS);
161  break;
162  case '-': /* see if "--verbose" */
163  if (strcmp (argv[i], "--verbose") == 0) {
164  verbose = 1;
165  }
166  else if (strcmp (argv[i], "--version") == 0) {
167  fprintf (stderr, "unibmpbump version %s\n\n", VERSION);
168  exit (EXIT_SUCCESS);
169  }
170  break;
171  default: /* if unrecognized option, print list and exit */
172  fprintf (stderr, "\nSyntax:\n\n");
173  fprintf (stderr, " unibmpbump ");
174  fprintf (stderr, "-i<Input_File> -o<Output_File>\n\n");
175  fprintf (stderr, "-v or --verbose gives verbose output");
176  fprintf (stderr, " on stderr\n\n");
177  fprintf (stderr, "-V or --version prints version");
178  fprintf (stderr, " on stderr and exits\n\n");
179  fprintf (stderr, "\nExample:\n\n");
180  fprintf (stderr, " unibmpbump -iuni0101.bmp");
181  fprintf (stderr, " -onew-uni0101.bmp\n\n");
182  exit (EXIT_SUCCESS);
183  }
184  }
185  }
186  }
187 
188  /*
189  Make sure we can open any I/O files that were specified before
190  doing anything else.
191  */
192  if (strlen (infile) > 0) {
193  if ((infp = fopen (infile, "r")) == NULL) {
194  fprintf (stderr, "Error: can't open %s for input.\n", infile);
195  exit (EXIT_FAILURE);
196  }
197  }
198  else {
199  infp = stdin;
200  }
201  if (strlen (outfile) > 0) {
202  if ((outfp = fopen (outfile, "w")) == NULL) {
203  fprintf (stderr, "Error: can't open %s for output.\n", outfile);
204  exit (EXIT_FAILURE);
205  }
206  }
207  else {
208  outfp = stdout;
209  }
210 
211 
212  /* Read bitmap file header */
213  file_format[0] = get_bytes (infp, 1);
214  file_format[1] = get_bytes (infp, 1);
215  file_format[2] = '\0'; /* Terminate string with null */
216 
217  /* Read file size */
218  filesize = get_bytes (infp, 4);
219 
220  /* Read Reserved bytes */
221  rsvd_hdr[0] = get_bytes (infp, 1);
222  rsvd_hdr[1] = get_bytes (infp, 1);
223  rsvd_hdr[2] = get_bytes (infp, 1);
224  rsvd_hdr[3] = get_bytes (infp, 1);
225 
226  /* Read Image Offset Address within file */
227  image_start = get_bytes (infp, 4);
228 
229  /*
230  See if this looks like a valid image file based on
231  the file header first two bytes.
232  */
233  if (strncmp (file_format, "BM", 2) != 0) {
234  fprintf (stderr, "\nInvalid file format: not file type \"BM\".\n\n");
235  exit (EXIT_FAILURE);
236  }
237 
238  if (verbose) {
239  fprintf (stderr, "\nFile Header:\n");
240  fprintf (stderr, " File Type: \"%s\"\n", file_format);
241  fprintf (stderr, " File Size: %d bytes\n", filesize);
242  fprintf (stderr, " Reserved: ");
243  for (i = 0; i < 4; i++) fprintf (stderr, " 0x%02X", rsvd_hdr[i]);
244  fputc ('\n', stderr);
245  fprintf (stderr, " Image Start: %d. = 0x%02X = 0%05o\n\n",
246  image_start, image_start, image_start);
247  } /* if (verbose) */
248 
249  /*
250  Device Independent Bitmap (DIB) Header: bitmap information header
251  ("BM" format file DIB Header is 12 bytes long).
252  */
253  dib_length = get_bytes (infp, 4);
254 
255  /*
256  Parse one of three versions of Device Independent Bitmap (DIB) format:
257 
258  Length Format
259  ------ ------
260  12 BITMAPCOREHEADER
261  40 BITMAPINFOHEADER
262  108 BITMAPV4HEADER
263  124 BITMAPV5HEADER
264  */
265  if (dib_length == 12) { /* BITMAPCOREHEADER format -- UNTESTED */
266  image_width = get_bytes (infp, 2);
267  image_height = get_bytes (infp, 2);
268  num_planes = get_bytes (infp, 2);
269  bits_per_pixel = get_bytes (infp, 2);
270  }
271  else if (dib_length >= 40) { /* BITMAPINFOHEADER format or later */
272  image_width = get_bytes (infp, 4);
273  image_height = get_bytes (infp, 4);
274  num_planes = get_bytes (infp, 2);
275  bits_per_pixel = get_bytes (infp, 2);
276  compression_method = get_bytes (infp, 4); /* BI_BITFIELDS */
277  image_size = get_bytes (infp, 4);
278  hres = get_bytes (infp, 4);
279  vres = get_bytes (infp, 4);
280  num_colors = get_bytes (infp, 4);
281  important_colors = get_bytes (infp, 4);
282 
283  /* true_colors is true number of colors in image */
284  if (num_colors == 0)
285  true_colors = 1 << bits_per_pixel;
286  else
287  true_colors = num_colors;
288 
289  /*
290  If dib_length > 40, the format is BITMAPV4HEADER or
291  BITMAPV5HEADER. As this program is only designed
292  to handle a monochrome image, we can ignore the rest
293  of the header but must read past the remaining bytes.
294  */
295  for (i = 40; i < dib_length; i++) (void)get_bytes (infp, 1);
296  }
297 
298  if (verbose) {
299  fprintf (stderr, "Device Independent Bitmap (DIB) Header:\n");
300  fprintf (stderr, " DIB Length: %9d bytes (version = ", dib_length);
301 
302  if (dib_length == 12) fprintf (stderr, "\"BITMAPCOREHEADER\")\n");
303  else if (dib_length == 40) fprintf (stderr, "\"BITMAPINFOHEADER\")\n");
304  else if (dib_length == 108) fprintf (stderr, "\"BITMAPV4HEADER\")\n");
305  else if (dib_length == 124) fprintf (stderr, "\"BITMAPV5HEADER\")\n");
306  else fprintf (stderr, "unknown)");
307  fprintf (stderr, " Bitmap Width: %6d pixels\n", image_width);
308  fprintf (stderr, " Bitmap Height: %6d pixels\n", image_height);
309  fprintf (stderr, " Color Planes: %6d\n", num_planes);
310  fprintf (stderr, " Bits per Pixel: %6d\n", bits_per_pixel);
311  fprintf (stderr, " Compression Method: %2d --> ", compression_method);
312  if (compression_method <= MAX_COMPRESSION_METHOD) {
313  fprintf (stderr, "%s", compression_type [compression_method]);
314  }
315  /*
316  Supported compression method values:
317  0 --> uncompressed RGB
318  11 --> uncompressed CMYK
319  */
320  if (compression_method == 0 || compression_method == 11) {
321  fprintf (stderr, " (no compression)");
322  }
323  else {
324  fprintf (stderr, "Image uses compression; this is unsupported.\n\n");
325  exit (EXIT_FAILURE);
326  }
327  fprintf (stderr, "\n");
328  fprintf (stderr, " Image Size: %5d bytes\n", image_size);
329  fprintf (stderr, " Horizontal Resolution: %5d pixels/meter\n", hres);
330  fprintf (stderr, " Vertical Resolution: %5d pixels/meter\n", vres);
331  fprintf (stderr, " Number of Colors: %5d", num_colors);
332  if (num_colors != true_colors) {
333  fprintf (stderr, " --> %d", true_colors);
334  }
335  fputc ('\n', stderr);
336  fprintf (stderr, " Important Colors: %5d", important_colors);
337  if (important_colors == 0)
338  fprintf (stderr, " (all colors are important)");
339  fprintf (stderr, "\n\n");
340  } /* if (verbose) */
341 
342  /*
343  Print Color Table information for images with pallettized colors.
344  */
345  if (bits_per_pixel <= 8) {
346  for (i = 0; i < 2; i++) {
347  color_map [i][0] = get_bytes (infp, 1);
348  color_map [i][1] = get_bytes (infp, 1);
349  color_map [i][2] = get_bytes (infp, 1);
350  color_map [i][3] = get_bytes (infp, 1);
351  }
352  /* Skip remaining color table entries if more than 2 */
353  while (i < true_colors) {
354  (void) get_bytes (infp, 4);
355  i++;
356  }
357 
358  if (color_map [0][0] >= 128) image_xor = 0xFF; /* Invert colors */
359  }
360 
361  if (verbose) {
362  fprintf (stderr, "Color Palette [R, G, B, %s] Values:\n",
363  (dib_length <= 40) ? "reserved" : "Alpha");
364  for (i = 0; i < 2; i++) {
365  fprintf (stderr, "%7d: [", i);
366  fprintf (stderr, "%3d,", color_map [i][0] & 0xFF);
367  fprintf (stderr, "%3d,", color_map [i][1] & 0xFF);
368  fprintf (stderr, "%3d,", color_map [i][2] & 0xFF);
369  fprintf (stderr, "%3d]\n", color_map [i][3] & 0xFF);
370  }
371  if (image_xor == 0xFF) fprintf (stderr, "Will Invert Colors.\n");
372  fputc ('\n', stderr);
373 
374  } /* if (verbose) */
375 
376 
377  /*
378  Check format before writing output file.
379  */
380  if (image_width != 560 && image_width != 576) {
381  fprintf (stderr, "\nUnsupported image width: %d\n", image_width);
382  fprintf (stderr, "Width should be 560 or 576 pixels.\n\n");
383  exit (EXIT_FAILURE);
384  }
385 
386  if (image_height != 544) {
387  fprintf (stderr, "\nUnsupported image height: %d\n", image_height);
388  fprintf (stderr, "Height should be 544 pixels.\n\n");
389  exit (EXIT_FAILURE);
390  }
391 
392  if (num_planes != 1) {
393  fprintf (stderr, "\nUnsupported number of planes: %d\n", num_planes);
394  fprintf (stderr, "Number of planes should be 1.\n\n");
395  exit (EXIT_FAILURE);
396  }
397 
398  if (bits_per_pixel != 1) {
399  fprintf (stderr, "\nUnsupported number of bits per pixel: %d\n",
400  bits_per_pixel);
401  fprintf (stderr, "Bits per pixel should be 1.\n\n");
402  exit (EXIT_FAILURE);
403  }
404 
405  if (compression_method != 0 && compression_method != 11) {
406  fprintf (stderr, "\nUnsupported compression method: %d\n",
407  compression_method);
408  fprintf (stderr, "Compression method should be 1 or 11.\n\n");
409  exit (EXIT_FAILURE);
410  }
411 
412  if (true_colors != 2) {
413  fprintf (stderr, "\nUnsupported number of colors: %d\n", true_colors);
414  fprintf (stderr, "Number of colors should be 2.\n\n");
415  exit (EXIT_FAILURE);
416  }
417 
418 
419  /*
420  If we made it this far, things look okay, so write out
421  the standard header for image conversion.
422  */
423  for (i = 0; i < 62; i++) fputc (standard_header[i], outfp);
424 
425 
426  /*
427  Image Data. Each row must be a multiple of 4 bytes, with
428  padding at the end of each row if necessary.
429  */
430  k = 0; /* byte number within the binary image */
431  for (i = 0; i < 544; i++) {
432  /*
433  If original image is 560 pixels wide (not 576), add
434  2 white bytes at beginning of row.
435  */
436  if (image_width == 560) { /* Insert 2 white bytes */
437  image_bytes[k++] = 0xFF;
438  image_bytes[k++] = 0xFF;
439  }
440  for (j = 0; j < 70; j++) { /* Copy next 70 bytes */
441  image_bytes[k++] = (get_bytes (infp, 1) & 0xFF) ^ image_xor;
442  }
443  /*
444  If original image is 560 pixels wide (not 576), skip
445  2 padding bytes at end of row in file because we inserted
446  2 white bytes at the beginning of the row.
447  */
448  if (image_width == 560) {
449  (void) get_bytes (infp, 2);
450  }
451  else { /* otherwise, next 2 bytes are part of the image so copy them */
452  image_bytes[k++] = (get_bytes (infp, 1) & 0xFF) ^ image_xor;
453  image_bytes[k++] = (get_bytes (infp, 1) & 0xFF) ^ image_xor;
454  }
455  }
456 
457 
458  /*
459  Change the image to match the unihex2bmp.c format if original wasn't
460  */
461  if (image_width == 560) {
462  regrid (image_bytes);
463  }
464 
465  for (i = 0; i < 544 * 576 / 8; i++) {
466  fputc (image_bytes[i], outfp);
467  }
468 
469 
470  /*
471  Wrap up.
472  */
473  fclose (infp);
474  fclose (outfp);
475 
476  exit (EXIT_SUCCESS);
477 }

◆ regrid()

void regrid ( unsigned *  image_bytes)

After reading in the image, shift it.

This function adjusts the input image from an original PNG file to match unihex2bmp.c format.

Parameters
[in,out]image_bytesThe pixels in an image.

Definition at line 514 of file unibmpbump.c.

514  {
515  int i, j, k; /* loop variables */
516  int offset;
517  unsigned glyph_row; /* one grid row of 32 pixels */
518  unsigned last_pixel; /* last pixel in a byte, to preserve */
519 
520  /* To insert "00" after "U+" at top of image */
521  char zero_pattern[16] = {
522  0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42,
523  0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00
524  };
525 
526  /* This is the horizontal grid pattern on glyph boundaries */
527  unsigned hgrid[72] = {
528  /* 0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
529  /* 8 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
530  /* 16 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
531  /* 24 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
532  /* 32 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
533  /* 40 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
534  /* 48 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
535  /* 56 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00,
536  /* 64 */ 0x00, 0x81, 0x81, 0x00, 0x00, 0x81, 0x81, 0x00
537  };
538 
539 
540  /*
541  First move "U+" left and insert "00" after it.
542  */
543  j = 15; /* rows are written bottom to top, so we'll decrement j */
544  for (i = 543 - 8; i > 544 - 24; i--) {
545  offset = 72 * i;
546  image_bytes [offset + 0] = image_bytes [offset + 2];
547  image_bytes [offset + 1] = image_bytes [offset + 3];
548  image_bytes [offset + 2] = image_bytes [offset + 4];
549  image_bytes [offset + 3] = image_bytes [offset + 4] =
550  ~zero_pattern[15 - j--] & 0xFF;
551  }
552 
553  /*
554  Now move glyph bitmaps to the right by 8 pixels.
555  */
556  for (i = 0; i < 16; i++) { /* for each glyph row */
557  for (j = 0; j < 16; j++) { /* for each glyph column */
558  /* set offset to lower left-hand byte of next glyph */
559  offset = (32 * 72 * i) + (9 * 72) + (4 * j) + 8;
560  for (k = 0; k < 16; k++) { /* for each glyph row */
561  glyph_row = (image_bytes [offset + 0] << 24) |
562  (image_bytes [offset + 1] << 16) |
563  (image_bytes [offset + 2] << 8) |
564  (image_bytes [offset + 3]);
565  last_pixel = glyph_row & 1; /* preserve border */
566  glyph_row >>= 4;
567  glyph_row &= 0x0FFFFFFE;
568  /* Set left 4 pixels to white and preserve last pixel */
569  glyph_row |= 0xF0000000 | last_pixel;
570  image_bytes [offset + 3] = glyph_row & 0xFF;
571  glyph_row >>= 8;
572  image_bytes [offset + 2] = glyph_row & 0xFF;
573  glyph_row >>= 8;
574  image_bytes [offset + 1] = glyph_row & 0xFF;
575  glyph_row >>= 8;
576  image_bytes [offset + 0] = glyph_row & 0xFF;
577  offset += 72; /* move up to next row in current glyph */
578  }
579  }
580  }
581 
582  /* Replace horizontal grid with unihex2bmp.c grid */
583  for (i = 0; i <= 16; i++) {
584  offset = 32 * 72 * i;
585  for (j = 0; j < 72; j++) {
586  image_bytes [offset + j] = hgrid [j];
587  }
588  }
589 
590  return;
591 }
VERSION
#define VERSION
Version of this program.
Definition: unibmpbump.c:38
MAX_COMPRESSION_METHOD
#define MAX_COMPRESSION_METHOD
Maximum supported compression method.
Definition: unibmpbump.c:40
get_bytes
unsigned get_bytes(FILE *infp, int nbytes)
Get from 1 to 4 bytes, inclusive, from input file.
Definition: unibmpbump.c:487
regrid
void regrid(unsigned *image_bytes)
After reading in the image, shift it.
Definition: unibmpbump.c:514