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