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