xref: /potrace-1.14/src/greymap.c (revision b3fce824)
1 /* Copyright (C) 2001-2017 Peter Selinger.
2    This file is part of Potrace. It is free software and it is covered
3    by the GNU General Public License. See the file COPYING for details. */
4 
5 
6 /* Routines for manipulating greymaps, including reading pgm files. We
7    only deal with greymaps of depth 8 bits. */
8 
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <stdlib.h>
14 #include <string.h>
15 #include <math.h>
16 #include <errno.h>
17 #include <stddef.h>
18 
19 #include "greymap.h"
20 #include "bitops.h"
21 
22 #define INTBITS (8*sizeof(int))
23 
24 #define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
25 
26 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
27 static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
28 
29 #define TRY(x) if (x) goto try_error
30 #define TRY_EOF(x) if (x) goto eof
31 #define TRY_STD(x) if (x) goto std_error
32 
33 /* ---------------------------------------------------------------------- */
34 /* basic greymap routines */
35 
36 /* calculate the size, in bytes, required for the data area of a
37    greymap of the given dy and h. Assume h >= 0. Return -1 if the size
38    does not fit into the ptrdiff_t type. */
getsize(int dy,int h)39 static inline ptrdiff_t getsize(int dy, int h) {
40   ptrdiff_t size;
41 
42   if (dy < 0) {
43     dy = -dy;
44   }
45 
46   size = (ptrdiff_t)dy * (ptrdiff_t)h * (ptrdiff_t)sizeof(gm_sample_t);
47 
48   /* check for overflow error */
49   if (size < 0 || (h != 0 && dy != 0 && size / h / dy != sizeof(gm_sample_t))) {
50     return -1;
51   }
52 
53   return size;
54 }
55 
56 /* return the size, in bytes, of the data area of the greymap. Return
57    -1 if the size does not fit into the ptrdiff_t type; however, this
58    cannot happen if the bitmap is well-formed, i.e., if created with
59    gm_new or gm_dup. */
gm_size(const greymap_t * gm)60 static inline ptrdiff_t gm_size(const greymap_t *gm) {
61   return getsize(gm->dy, gm->h);
62 }
63 
64 
65 
66 /* return new greymap initialized to 0. NULL with errno on error.
67    Assumes w, h >= 0. */
gm_new(int w,int h)68 greymap_t *gm_new(int w, int h) {
69   greymap_t *gm;
70   int dy = w;
71   ptrdiff_t size;
72 
73   size = getsize(dy, h);
74   if (size < 0) {
75     errno = ENOMEM;
76     return NULL;
77   }
78   if (size == 0) {
79     size = 1; /* make surecmalloc() doesn't return NULL */
80   }
81 
82   gm = (greymap_t *) malloc(sizeof(greymap_t));
83   if (!gm) {
84     return NULL;
85   }
86   gm->w = w;
87   gm->h = h;
88   gm->dy = dy;
89   gm->base = (gm_sample_t *) calloc(1, size);
90   if (!gm->base) {
91     free(gm);
92     return NULL;
93   }
94   gm->map = gm->base;
95   return gm;
96 }
97 
98 /* free the given greymap */
gm_free(greymap_t * gm)99 void gm_free(greymap_t *gm) {
100   if (gm) {
101     free(gm->base);
102   }
103   free(gm);
104 }
105 
106 /* duplicate the given greymap. Return NULL on error with errno set. */
gm_dup(greymap_t * gm)107 greymap_t *gm_dup(greymap_t *gm) {
108   greymap_t *gm1 = gm_new(gm->w, gm->h);
109   int y;
110 
111   if (!gm1) {
112     return NULL;
113   }
114   for (y=0; y<gm->h; y++) {
115     memcpy(gm_scanline(gm1, y), gm_scanline(gm, y), (size_t)gm1->dy * sizeof(gm_sample_t));
116   }
117   return gm1;
118 }
119 
120 /* clear the given greymap to color b. */
gm_clear(greymap_t * gm,int b)121 void gm_clear(greymap_t *gm, int b) {
122   ptrdiff_t size = gm_size(gm);
123   int x, y;
124 
125   if (b==0) {
126     memset(gm->base, 0, size);
127   } else {
128     for (y=0; y<gm->h; y++) {
129       for (x=0; x<gm->w; x++) {
130         GM_UPUT(gm, x, y, b);
131       }
132     }
133   }
134 }
135 
136 /* turn the given greymap upside down. This does not move the pixel
137    data or change the base address. */
gm_flip(greymap_t * gm)138 static inline void gm_flip(greymap_t *gm) {
139   int dy = gm->dy;
140 
141   if (gm->h == 0 || gm->h == 1) {
142     return;
143   }
144 
145   gm->map = gm_scanline(gm, gm->h - 1);
146   gm->dy = -dy;
147 }
148 
149 /* resize the greymap to the given new height. The pixel data remains
150    bottom-aligned (truncated at the top) when dy >= 0 and top-aligned
151    (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on
152    error with errno set. If the new height is <= the old one, no error
153    should occur. If the new height is larger, the additional pixel
154    data is *not* initialized. */
gm_resize(greymap_t * gm,int h)155 static inline int gm_resize(greymap_t *gm, int h) {
156   int dy = gm->dy;
157   ptrdiff_t newsize;
158   gm_sample_t *newbase;
159 
160   if (dy < 0) {
161     gm_flip(gm);
162   }
163 
164   newsize = getsize(dy, h);
165   if (newsize < 0) {
166     errno = ENOMEM;
167     goto error;
168   }
169   if (newsize == 0) {
170     newsize = 1; /* make sure realloc() doesn't return NULL */
171   }
172 
173   newbase = (gm_sample_t *)realloc(gm->base, newsize);
174   if (newbase == NULL) {
175     goto error;
176   }
177   gm->base = newbase;
178   gm->map = newbase;
179   gm->h = h;
180 
181   if (dy < 0) {
182     gm_flip(gm);
183   }
184   return 0;
185 
186  error:
187   if (dy < 0) {
188     gm_flip(gm);
189   }
190   return 1;
191 }
192 
193 
194 /* ---------------------------------------------------------------------- */
195 /* routines for reading pnm streams */
196 
197 /* read next character after whitespace and comments. Return EOF on
198    end of file or error. */
fgetc_ws(FILE * f)199 static int fgetc_ws(FILE *f) {
200   int c;
201 
202   while (1) {
203     c = fgetc(f);
204     if (c=='#') {
205       while (1) {
206 	c = fgetc(f);
207 	if (c=='\n' || c==EOF) {
208 	  break;
209 	}
210       }
211     }
212     /* space, tab, line feed, carriage return, form-feed */
213     if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
214       return c;
215     }
216   }
217 }
218 
219 /* skip whitespace and comments, then read a non-negative decimal
220    number from a stream. Return -1 on EOF. Tolerate other errors (skip
221    bad characters). Do not the read any characters following the
222    number (put next character back into the stream) */
223 
readnum(FILE * f)224 static int readnum(FILE *f) {
225   int c;
226   int acc;
227 
228   /* skip whitespace and comments */
229   while (1) {
230     c = fgetc_ws(f);
231     if (c==EOF) {
232       return -1;
233     }
234     if (c>='0' && c<='9') {
235       break;
236     }
237   }
238 
239   /* first digit is already in c */
240   acc = c-'0';
241   while (1) {
242     c = fgetc(f);
243     if (c==EOF) {
244       break;
245     }
246     if (c<'0' || c>'9') {
247       ungetc(c, f);
248       break;
249     }
250     acc *= 10;
251     acc += c-'0';
252   }
253   return acc;
254 }
255 
256 /* similar to readnum, but read only a single 0 or 1, and do not read
257    any characters after it. */
258 
readbit(FILE * f)259 static int readbit(FILE *f) {
260   int c;
261 
262   /* skip whitespace and comments */
263   while (1) {
264     c = fgetc_ws(f);
265     if (c==EOF) {
266       return -1;
267     }
268     if (c>='0' && c<='1') {
269       break;
270     }
271   }
272 
273   return c-'0';
274 }
275 
276 /* ---------------------------------------------------------------------- */
277 
278 /* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
279    convert the output to a greymap. Return greymap in *gmp. Return 0
280    on success, -1 on error with errno set, -2 on bad file format (with
281    error message in gm_read_error), and 1 on premature end of file, -3
282    on empty file (including files with only whitespace and comments),
283    -4 if wrong magic number. If the return value is >=0, *gmp is
284    valid. */
285 
286 const char *gm_read_error = NULL;
287 
gm_read(FILE * f,greymap_t ** gmp)288 int gm_read(FILE *f, greymap_t **gmp) {
289   int magic[2];
290 
291   /* read magic number. We ignore whitespace and comments before the
292      magic, for the benefit of concatenated files in P1-P3 format.
293      Multiple P1-P3 images in a single file are not formally allowed
294      by the PNM standard, but there is no harm in being lenient. */
295 
296   magic[0] = fgetc_ws(f);
297   if (magic[0] == EOF) {
298     /* files which contain only comments and whitespace count as "empty" */
299     return -3;
300   }
301   magic[1] = fgetc(f);
302   if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
303     return gm_readbody_pnm(f, gmp, magic[1]);
304   }
305   if (magic[0] == 'B' && magic[1] == 'M') {
306     return gm_readbody_bmp(f, gmp);
307   }
308   return -4;
309 }
310 
311 /* ---------------------------------------------------------------------- */
312 /* read PNM format */
313 
314 /* read PNM stream after magic number. Return values as for gm_read */
gm_readbody_pnm(FILE * f,greymap_t ** gmp,int magic)315 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
316   greymap_t *gm;
317   int x, y, i, j, b, b1, sum;
318   int bpr; /* bytes per row (as opposed to 4*gm->c) */
319   int w, h, max;
320   int realheight;  /* in case of incomplete file, keeps track of how
321                       many scan lines actually contain data */
322 
323   gm = NULL;
324 
325   w = readnum(f);
326   if (w<0) {
327     goto format_error;
328   }
329 
330   h = readnum(f);
331   if (h<0) {
332     goto format_error;
333   }
334 
335   /* allocate greymap */
336   gm = gm_new(w, h);
337   if (!gm) {
338     goto std_error;
339   }
340 
341   realheight = 0;
342 
343   switch (magic) {
344   default:
345     /* not reached */
346     goto format_error;
347 
348   case '1':
349     /* read P1 format: PBM ascii */
350 
351     for (y=0; y<h; y++) {
352       realheight = y+1;
353       for (x=0; x<w; x++) {
354 	b = readbit(f);
355 	if (b<0) {
356 	  goto eof;
357 	}
358 	GM_UPUT(gm, x, y, b ? 0 : 255);
359       }
360     }
361     break;
362 
363   case '2':
364     /* read P2 format: PGM ascii */
365 
366     max = readnum(f);
367     if (max<1) {
368       goto format_error;
369     }
370 
371     for (y=0; y<h; y++) {
372       realheight = y+1;
373       for (x=0; x<w; x++) {
374         b = readnum(f);
375         if (b<0) {
376           goto eof;
377         }
378         GM_UPUT(gm, x, y, b*255/max);
379       }
380     }
381     break;
382 
383   case '3':
384     /* read P3 format: PPM ascii */
385 
386     max = readnum(f);
387     if (max<1) {
388       goto format_error;
389     }
390 
391     for (y=0; y<h; y++) {
392       realheight = y+1;
393       for (x=0; x<w; x++) {
394 	sum = 0;
395 	for (i=0; i<3; i++) {
396 	  b = readnum(f);
397 	  if (b<0) {
398 	    goto eof;
399 	  }
400 	  sum += b;
401 	}
402         GM_UPUT(gm, x, y, sum*(255/3)/max);
403       }
404     }
405     break;
406 
407   case '4':
408     /* read P4 format: PBM raw */
409 
410     b = fgetc(f);  /* read single white-space character after height */
411     if (b==EOF) {
412       goto format_error;
413     }
414 
415     bpr = (w+7)/8;
416 
417     for (y=0; y<h; y++) {
418       realheight = y+1;
419       for (i=0; i<bpr; i++) {
420 	b = fgetc(f);
421 	if (b==EOF) {
422 	  goto eof;
423 	}
424 	for (j=0; j<8; j++) {
425 	  GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
426 	}
427       }
428     }
429     break;
430 
431   case '5':
432     /* read P5 format: PGM raw */
433 
434     max = readnum(f);
435     if (max<1) {
436       goto format_error;
437     }
438 
439     b = fgetc(f);  /* read single white-space character after max */
440     if (b==EOF) {
441       goto format_error;
442     }
443 
444     for (y=0; y<h; y++) {
445       realheight = y+1;
446       for (x=0; x<w; x++) {
447         b = fgetc(f);
448         if (b==EOF)
449           goto eof;
450         if (max>=256) {
451           b <<= 8;
452           b1 = fgetc(f);
453           if (b1==EOF)
454             goto eof;
455           b |= b1;
456         }
457         GM_UPUT(gm, x, y, b*255/max);
458       }
459     }
460     break;
461 
462   case '6':
463     /* read P6 format: PPM raw */
464 
465     max = readnum(f);
466     if (max<1) {
467       goto format_error;
468     }
469 
470     b = fgetc(f);  /* read single white-space character after max */
471     if (b==EOF) {
472       goto format_error;
473     }
474 
475     for (y=0; y<h; y++) {
476       realheight = y+1;
477       for (x=0; x<w; x++) {
478         sum = 0;
479         for (i=0; i<3; i++) {
480           b = fgetc(f);
481           if (b==EOF) {
482             goto eof;
483 	  }
484           if (max>=256) {
485             b <<= 8;
486             b1 = fgetc(f);
487             if (b1==EOF)
488               goto eof;
489             b |= b1;
490           }
491           sum += b;
492         }
493         GM_UPUT(gm, x, y, sum*(255/3)/max);
494       }
495     }
496     break;
497   }
498 
499   gm_flip(gm);
500   *gmp = gm;
501   return 0;
502 
503  eof:
504   TRY_STD(gm_resize(gm, realheight));
505   gm_flip(gm);
506   *gmp = gm;
507   return 1;
508 
509  format_error:
510   gm_free(gm);
511   if (magic == '1' || magic == '4') {
512     gm_read_error = "invalid pbm file";
513   } else if (magic == '2' || magic == '5') {
514     gm_read_error = "invalid pgm file";
515   } else {
516     gm_read_error = "invalid ppm file";
517   }
518   return -2;
519 
520  std_error:
521   gm_free(gm);
522   return -1;
523 }
524 
525 /* ---------------------------------------------------------------------- */
526 /* read BMP format */
527 
528 struct bmp_info_s {
529   unsigned int FileSize;
530   unsigned int reserved;
531   unsigned int DataOffset;
532   unsigned int InfoSize;
533   unsigned int w;              /* width */
534   unsigned int h;              /* height */
535   unsigned int Planes;
536   unsigned int bits;           /* bits per sample */
537   unsigned int comp;           /* compression mode */
538   unsigned int ImageSize;
539   unsigned int XpixelsPerM;
540   unsigned int YpixelsPerM;
541   unsigned int ncolors;        /* number of colors in palette */
542   unsigned int ColorsImportant;
543   unsigned int RedMask;
544   unsigned int GreenMask;
545   unsigned int BlueMask;
546   unsigned int AlphaMask;
547   unsigned int ctbits;         /* sample size for color table */
548   int topdown;                 /* top-down mode? */
549 };
550 typedef struct bmp_info_s bmp_info_t;
551 
552 /* auxiliary */
553 
554 static int bmp_count = 0; /* counter for byte padding */
555 static int bmp_pos = 0;   /* counter from start of BMP data */
556 
557 /* read n-byte little-endian integer. Return 1 on EOF or error, else
558    0. Assume n<=4. */
bmp_readint(FILE * f,int n,unsigned int * p)559 static int bmp_readint(FILE *f, int n, unsigned int *p) {
560   int i;
561   unsigned int sum = 0;
562   int b;
563 
564   for (i=0; i<n; i++) {
565     b = fgetc(f);
566     if (b==EOF) {
567       return 1;
568     }
569     sum += (unsigned)b << (8*i);
570   }
571   bmp_count += n;
572   bmp_pos += n;
573   *p = sum;
574   return 0;
575 }
576 
577 /* reset padding boundary */
bmp_pad_reset(void)578 static void bmp_pad_reset(void) {
579   bmp_count = 0;
580 }
581 
582 /* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
583    else 0. */
bmp_pad(FILE * f)584 static int bmp_pad(FILE *f) {
585   int c, i, b;
586 
587   c = (-bmp_count) & 3;
588   for (i=0; i<c; i++) {
589     b = fgetc(f);
590     if (b==EOF) {
591       return 1;
592     }
593   }
594   bmp_pos += c;
595   bmp_count = 0;
596   return 0;
597 }
598 
599 /* forward to the new file position. Return 1 on EOF or error, else 0 */
bmp_forward(FILE * f,int pos)600 static int bmp_forward(FILE *f, int pos) {
601   int b;
602 
603   while (bmp_pos < pos) {
604     b = fgetc(f);
605     if (b==EOF) {
606       return 1;
607     }
608     bmp_pos++;
609     bmp_count++;
610   }
611   return 0;
612 }
613 
614 /* safe colortable access */
615 #define COLTABLE(c) ((c) < bmpinfo.ncolors ? coltable[(c)] : 0)
616 
617 /* read BMP stream after magic number. Return values as for gm_read.
618    We choose to be as permissive as possible, since there are many
619    programs out there which produce BMP. For instance, ppmtobmp can
620    produce codings with anywhere from 1-8 or 24 bits per sample,
621    although most specifications only allow 1,4,8,24,32. We can also
622    read both the old and new OS/2 BMP formats in addition to the
623    Windows BMP format. */
gm_readbody_bmp(FILE * f,greymap_t ** gmp)624 static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
625   bmp_info_t bmpinfo;
626   int *coltable;
627   unsigned int b, c;
628   unsigned int i, j;
629   greymap_t *gm;
630   unsigned int x, y;
631   int col[2];
632   unsigned int bitbuf;
633   unsigned int n;
634   unsigned int redshift, greenshift, blueshift;
635   int realheight;  /* in case of incomplete file, keeps track of how
636                       many scan lines actually contain data */
637 
638   gm_read_error = NULL;
639   gm = NULL;
640   coltable = NULL;
641 
642   bmp_pos = 2;  /* set file position */
643 
644   /* file header (minus magic number) */
645   TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
646   TRY(bmp_readint(f, 4, &bmpinfo.reserved));
647   TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
648 
649   /* info header */
650   TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
651   if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64
652       || bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124) {
653     /* Windows or new OS/2 format */
654     bmpinfo.ctbits = 32; /* sample size in color table */
655     TRY(bmp_readint(f, 4, &bmpinfo.w));
656     TRY(bmp_readint(f, 4, &bmpinfo.h));
657     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
658     TRY(bmp_readint(f, 2, &bmpinfo.bits));
659     TRY(bmp_readint(f, 4, &bmpinfo.comp));
660     TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
661     TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
662     TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
663     TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
664     TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
665     if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */
666       TRY(bmp_readint(f, 4, &bmpinfo.RedMask));
667       TRY(bmp_readint(f, 4, &bmpinfo.GreenMask));
668       TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
669       TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
670     }
671     if (bmpinfo.w > 0x7fffffff) {
672       goto format_error;
673     }
674     if (bmpinfo.h > 0x7fffffff) {
675       bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
676       bmpinfo.topdown = 1;
677     } else {
678       bmpinfo.topdown = 0;
679     }
680     if (bmpinfo.h > 0x7fffffff) {
681       goto format_error;
682     }
683   } else if (bmpinfo.InfoSize == 12) {
684     /* old OS/2 format */
685     bmpinfo.ctbits = 24; /* sample size in color table */
686     TRY(bmp_readint(f, 2, &bmpinfo.w));
687     TRY(bmp_readint(f, 2, &bmpinfo.h));
688     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
689     TRY(bmp_readint(f, 2, &bmpinfo.bits));
690     bmpinfo.comp = 0;
691     bmpinfo.ncolors = 0;
692     bmpinfo.topdown = 0;
693   } else {
694     goto format_error;
695   }
696 
697   if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) {
698     /* bitfield feature is only understood with V4 and V5 format */
699     goto format_error;
700   }
701 
702   if (bmpinfo.comp > 3 || bmpinfo.bits > 32) {
703     goto format_error;
704   }
705 
706   /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
707   TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
708 
709   if (bmpinfo.Planes != 1) {
710     gm_read_error = "cannot handle bmp planes";
711     goto format_error;  /* can't handle planes */
712   }
713 
714   if (bmpinfo.ncolors == 0 && bmpinfo.bits <= 8) {
715     bmpinfo.ncolors = 1 << bmpinfo.bits;
716   }
717 
718   /* color table, present only if bmpinfo.bits <= 8. */
719   if (bmpinfo.bits <= 8) {
720     coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
721     if (!coltable) {
722       goto std_error;
723     }
724     /* NOTE: since we are reading a greymap, we can immediately convert
725        the color table entries to grey values. */
726     for (i=0; i<bmpinfo.ncolors; i++) {
727       TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
728       c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
729       coltable[i] = c/3;
730     }
731   }
732 
733   /* forward to data */
734   if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
735     TRY(bmp_forward(f, bmpinfo.DataOffset));
736   }
737 
738   /* allocate greymap */
739   gm = gm_new(bmpinfo.w, bmpinfo.h);
740   if (!gm) {
741     goto std_error;
742   }
743 
744   realheight = 0;
745 
746   switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
747 
748   default:
749     goto format_error;
750     break;
751 
752   case 0x001:  /* monochrome palette */
753 
754     /* raster data */
755     for (y=0; y<bmpinfo.h; y++) {
756       realheight = y+1;
757       bmp_pad_reset();
758       for (i=0; 8*i<bmpinfo.w; i++) {
759 	TRY_EOF(bmp_readint(f, 1, &b));
760 	for (j=0; j<8; j++) {
761 	  GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? COLTABLE(1) : COLTABLE(0));
762 	}
763       }
764       TRY(bmp_pad(f));
765     }
766     break;
767 
768   case 0x002:  /* 2-bit to 8-bit palettes */
769   case 0x003:
770   case 0x004:
771   case 0x005:
772   case 0x006:
773   case 0x007:
774   case 0x008:
775     for (y=0; y<bmpinfo.h; y++) {
776       realheight = y+1;
777       bmp_pad_reset();
778       bitbuf = 0;  /* bit buffer: bits in buffer are high-aligned */
779       n = 0;       /* number of bits currently in bitbuffer */
780       for (x=0; x<bmpinfo.w; x++) {
781 	if (n < bmpinfo.bits) {
782 	  TRY_EOF(bmp_readint(f, 1, &b));
783 	  bitbuf |= b << (INTBITS - 8 - n);
784 	  n += 8;
785 	}
786 	b = bitbuf >> (INTBITS - bmpinfo.bits);
787 	bitbuf <<= bmpinfo.bits;
788 	n -= bmpinfo.bits;
789 	GM_UPUT(gm, x, y, COLTABLE(b));
790       }
791       TRY(bmp_pad(f));
792     }
793     break;
794 
795   case 0x010:  /* 16-bit encoding */
796     /* can't do this format because it is not well-documented and I
797        don't have any samples */
798     gm_read_error = "cannot handle bmp 16-bit coding";
799     goto format_error;
800     break;
801 
802   case 0x018:  /* 24-bit encoding */
803   case 0x020:  /* 32-bit encoding */
804     for (y=0; y<bmpinfo.h; y++) {
805       realheight = y+1;
806       bmp_pad_reset();
807       for (x=0; x<bmpinfo.w; x++) {
808         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
809 	c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
810         GM_UPUT(gm, x, y, c/3);
811       }
812       TRY(bmp_pad(f));
813     }
814     break;
815 
816   case 0x320:  /* 32-bit encoding with bitfields */
817     redshift = lobit(bmpinfo.RedMask);
818     greenshift = lobit(bmpinfo.GreenMask);
819     blueshift = lobit(bmpinfo.BlueMask);
820 
821     for (y=0; y<bmpinfo.h; y++) {
822       realheight = y+1;
823       bmp_pad_reset();
824       for (x=0; x<bmpinfo.w; x++) {
825         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
826 	c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
827         GM_UPUT(gm, x, y, c/3);
828       }
829       TRY(bmp_pad(f));
830     }
831     break;
832 
833   case 0x204:  /* 4-bit runlength compressed encoding (RLE4) */
834     x = 0;
835     y = 0;
836     while (1) {
837       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
838       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
839       if (b>0) {
840 	/* repeat count */
841 	col[0] = COLTABLE((c>>4) & 0xf);
842 	col[1] = COLTABLE(c & 0xf);
843 	for (i=0; i<b && x<bmpinfo.w; i++) {
844 	  if (x>=bmpinfo.w) {
845 	    x=0;
846 	    y++;
847 	  }
848 	  if (y>=bmpinfo.h) {
849 	    break;
850 	  }
851           realheight = y+1;
852 	  GM_UPUT(gm, x, y, col[i&1]);
853 	  x++;
854 	}
855       } else if (c == 0) {
856 	/* end of line */
857 	y++;
858 	x = 0;
859       } else if (c == 1) {
860 	/* end of greymap */
861 	break;
862       } else if (c == 2) {
863 	/* "delta": skip pixels in x and y directions */
864 	TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
865 	TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
866 	x += b;
867 	y += c;
868       } else {
869 	/* verbatim segment */
870 	for (i=0; i<c; i++) {
871 	  if ((i&1)==0) {
872 	    TRY_EOF(bmp_readint(f, 1, &b));
873 	  }
874 	  if (x>=bmpinfo.w) {
875 	    x=0;
876 	    y++;
877 	  }
878 	  if (y>=bmpinfo.h) {
879 	    break;
880 	  }
881           realheight = y+1;
882 	  GM_PUT(gm, x, y, COLTABLE((b>>(4-4*(i&1))) & 0xf));
883 	  x++;
884 	}
885 	if ((c+1) & 2) {
886 	  /* pad to 16-bit boundary */
887 	  TRY_EOF(bmp_readint(f, 1, &b));
888 	}
889       }
890     }
891     break;
892 
893   case 0x108:  /* 8-bit runlength compressed encoding (RLE8) */
894     x = 0;
895     y = 0;
896     while (1) {
897       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
898       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
899       if (b>0) {
900 	/* repeat count */
901 	for (i=0; i<b; i++) {
902 	  if (x>=bmpinfo.w) {
903 	    x=0;
904 	    y++;
905 	  }
906 	  if (y>=bmpinfo.h) {
907 	    break;
908 	  }
909           realheight = y+1;
910 	  GM_UPUT(gm, x, y, COLTABLE(c));
911 	  x++;
912 	}
913       } else if (c == 0) {
914 	/* end of line */
915 	y++;
916 	x = 0;
917       } else if (c == 1) {
918 	/* end of greymap */
919 	break;
920       } else if (c == 2) {
921 	/* "delta": skip pixels in x and y directions */
922 	TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
923 	TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
924 	x += b;
925 	y += c;
926       } else {
927 	/* verbatim segment */
928 	for (i=0; i<c; i++) {
929 	  TRY_EOF(bmp_readint(f, 1, &b));
930           if (x>=bmpinfo.w) {
931             x=0;
932             y++;
933           }
934           if (y>=bmpinfo.h) {
935             break;
936           }
937           realheight = y+1;
938 	  GM_PUT(gm, x, y, COLTABLE(b));
939 	  x++;
940 	}
941 	if (c & 1) {
942 	  /* pad input to 16-bit boundary */
943 	  TRY_EOF(bmp_readint(f, 1, &b));
944 	}
945       }
946     }
947     break;
948 
949   } /* switch */
950 
951   /* skip any potential junk after the data section, but don't
952      complain in case EOF is encountered */
953   bmp_forward(f, bmpinfo.FileSize);
954 
955   free(coltable);
956   if (bmpinfo.topdown) {
957     gm_flip(gm);
958   }
959   *gmp = gm;
960   return 0;
961 
962  eof:
963   TRY_STD(gm_resize(gm, realheight));
964   free(coltable);
965   if (bmpinfo.topdown) {
966     gm_flip(gm);
967   }
968   *gmp = gm;
969   return 1;
970 
971  format_error:
972  try_error:
973   free(coltable);
974   gm_free(gm);
975   if (!gm_read_error) {
976     gm_read_error = "invalid bmp file";
977   }
978   return -2;
979 
980  std_error:
981   free(coltable);
982   gm_free(gm);
983   return -1;
984 }
985 
986 /* ---------------------------------------------------------------------- */
987 
988 /* write a pgm stream, either P2 or (if raw != 0) P5 format. Include
989    one-line comment if non-NULL. Mode determines how out-of-range
990    color values are converted. Gamma is the desired gamma correction,
991    if any (set to 2.2 if the image is to look optimal on a CRT monitor,
992    2.8 for LCD). Set to 1.0 for no gamma correction */
993 
gm_writepgm(FILE * f,greymap_t * gm,const char * comment,int raw,int mode,double gamma)994 int gm_writepgm(FILE *f, greymap_t *gm, const char *comment, int raw, int mode, double gamma) {
995   int x, y, v;
996   int gammatable[256];
997 
998   /* prepare gamma correction lookup table */
999   if (gamma != 1.0) {
1000     gammatable[0] = 0;
1001     for (v=1; v<256; v++) {
1002       gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
1003     }
1004   } else {
1005     for (v=0; v<256; v++) {
1006       gammatable[v] = v;
1007     }
1008   }
1009 
1010   fprintf(f, raw ? "P5\n" : "P2\n");
1011   if (comment && *comment) {
1012     fprintf(f, "# %s\n", comment);
1013   }
1014   fprintf(f, "%d %d 255\n", gm->w, gm->h);
1015   for (y=gm->h-1; y>=0; y--) {
1016     for (x=0; x<gm->w; x++) {
1017       v = GM_UGET(gm, x, y);
1018       if (mode == GM_MODE_NONZERO) {
1019 	if (v > 255) {
1020 	  v = 510 - v;
1021 	}
1022 	if (v < 0) {
1023 	  v = 0;
1024 	}
1025       } else if (mode == GM_MODE_ODD) {
1026 	v = mod(v, 510);
1027 	if (v > 255) {
1028 	  v = 510 - v;
1029 	}
1030       } else if (mode == GM_MODE_POSITIVE) {
1031 	if (v < 0) {
1032 	  v = 0;
1033 	} else if (v > 255) {
1034 	  v = 255;
1035 	}
1036       } else if (mode == GM_MODE_NEGATIVE) {
1037 	v = 510 - v;
1038 	if (v < 0) {
1039 	  v = 0;
1040 	} else if (v > 255) {
1041 	  v = 255;
1042 	}
1043       }
1044       v = gammatable[v];
1045 
1046       if (raw) {
1047 	fputc(v, f);
1048       } else {
1049 	fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
1050       }
1051     }
1052   }
1053   return 0;
1054 }
1055 
1056 /* ---------------------------------------------------------------------- */
1057 /* output - for primitive debugging purposes only! */
1058 
1059 /* print greymap to screen */
gm_print(FILE * f,greymap_t * gm)1060 int gm_print(FILE *f, greymap_t *gm) {
1061   int x, y;
1062   int xx, yy;
1063   int d, t;
1064   int sw, sh;
1065 
1066   sw = gm->w < 79 ? gm->w : 79;
1067   sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
1068 
1069   for (yy=sh-1; yy>=0; yy--) {
1070     for (xx=0; xx<sw; xx++) {
1071       d=0;
1072       t=0;
1073       for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
1074 	for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
1075 	  d += GM_GET(gm, x, y);
1076 	  t += 256;
1077 	}
1078       }
1079       fputc("*#=- "[5*d/t], f);  /* what a cute trick :) */
1080     }
1081     fputc('\n', f);
1082   }
1083   return 0;
1084 }
1085