xref: /potrace-1.14/src/bitmap_io.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 bitmaps, including reading pbm files. */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <stdio.h>
13 
14 #include "bitmap.h"
15 #include "bitops.h"
16 #include "bitmap_io.h"
17 
18 #define INTBITS (8*sizeof(int))
19 
20 static int bm_readbody_bmp(FILE *f, double threshold, potrace_bitmap_t **bmp);
21 static int bm_readbody_pnm(FILE *f, double threshold, potrace_bitmap_t **bmp, int magic);
22 
23 #define TRY(x) if (x) goto try_error
24 #define TRY_EOF(x) if (x) goto eof
25 #define TRY_STD(x) if (x) goto std_error
26 
27 /* ---------------------------------------------------------------------- */
28 /* routines for reading pnm streams */
29 
30 /* read next character after whitespace and comments. Return EOF on
31    end of file or error. */
fgetc_ws(FILE * f)32 static int fgetc_ws(FILE *f) {
33   int c;
34 
35   while (1) {
36     c = fgetc(f);
37     if (c=='#') {
38       while (1) {
39 	c = fgetc(f);
40 	if (c=='\n' || c==EOF) {
41 	  break;
42 	}
43       }
44     }
45     /* space, tab, line feed, carriage return, form-feed */
46     if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
47       return c;
48     }
49   }
50 }
51 
52 /* skip whitespace and comments, then read a non-negative decimal
53    number from a stream. Return -1 on EOF. Tolerate other errors (skip
54    bad characters). Do not the read any characters following the
55    number (put next character back into the stream) */
56 
readnum(FILE * f)57 static int readnum(FILE *f) {
58   int c;
59   int acc;
60 
61   /* skip whitespace and comments */
62   while (1) {
63     c = fgetc_ws(f);
64     if (c==EOF) {
65       return -1;
66     }
67     if (c>='0' && c<='9') {
68       break;
69     }
70   }
71 
72   /* first digit is already in c */
73   acc = c-'0';
74   while (1) {
75     c = fgetc(f);
76     if (c==EOF) {
77       break;
78     }
79     if (c<'0' || c>'9') {
80       ungetc(c, f);
81       break;
82     }
83     acc *= 10;
84     acc += c-'0';
85   }
86   return acc;
87 }
88 
89 /* similar to readnum, but read only a single 0 or 1, and do not read
90    any characters after it. */
91 
readbit(FILE * f)92 static int readbit(FILE *f) {
93   int c;
94 
95   /* skip whitespace and comments */
96   while (1) {
97     c = fgetc_ws(f);
98     if (c==EOF) {
99       return -1;
100     }
101     if (c>='0' && c<='1') {
102       break;
103     }
104   }
105 
106   return c-'0';
107 }
108 
109 /* ---------------------------------------------------------------------- */
110 
111 /* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
112    convert the output to a bitmap. Return bitmap in *bmp. Return 0 on
113    success, -1 on error with errno set, -2 on bad file format (with
114    error message in bm_read_error), and 1 on premature end of file, -3
115    on empty file (including files which contain only whitespace and
116    comments), -4 if wrong magic number. If the return value is >=0,
117    *bmp is valid. */
118 
119 const char *bm_read_error = NULL;
120 
bm_read(FILE * f,double threshold,potrace_bitmap_t ** bmp)121 int bm_read(FILE *f, double threshold, potrace_bitmap_t **bmp) {
122   int magic[2];
123 
124   /* read magic number. We ignore whitespace and comments before the
125      magic, for the benefit of concatenated files in P1-P3 format.
126      Multiple P1-P3 images in a single file are not formally allowed
127      by the PNM standard, but there is no harm in being lenient. */
128 
129   magic[0] = fgetc_ws(f);
130   if (magic[0] == EOF) {
131     return -3;
132   }
133   magic[1] = fgetc(f);
134   if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
135     return bm_readbody_pnm(f, threshold, bmp, magic[1]);
136   }
137   if (magic[0] == 'B' && magic[1] == 'M') {
138     return bm_readbody_bmp(f, threshold, bmp);
139   }
140   return -4;
141 }
142 
143 /* ---------------------------------------------------------------------- */
144 /* read PNM format */
145 
146 /* read PNM stream after magic number. Return values as for bm_read */
bm_readbody_pnm(FILE * f,double threshold,potrace_bitmap_t ** bmp,int magic)147 static int bm_readbody_pnm(FILE *f, double threshold, potrace_bitmap_t **bmp, int magic) {
148   potrace_bitmap_t *bm;
149   int x, y, i, b, b1, sum;
150   int bpr; /* bytes per row (as opposed to 4*bm->c) */
151   int w, h, max;
152   int realheight;  /* in case of incomplete file, keeps track of how
153                       many scan lines actually contain data */
154 
155   bm = NULL;
156 
157   w = readnum(f);
158   if (w<0) {
159     goto format_error;
160   }
161 
162   h = readnum(f);
163   if (h<0) {
164     goto format_error;
165   }
166 
167   /* allocate bitmap */
168   bm = bm_new(w, h);
169   if (!bm) {
170     goto std_error;
171   }
172 
173   realheight = 0;
174 
175   switch (magic) {
176   default:
177     /* not reached */
178     goto format_error;
179 
180   case '1':
181     /* read P1 format: PBM ascii */
182 
183     for (y=0; y<h; y++) {
184       realheight = y+1;
185       for (x=0; x<w; x++) {
186 	b = readbit(f);
187 	if (b<0) {
188 	  goto eof;
189 	}
190 	BM_UPUT(bm, x, y, b);
191       }
192     }
193     break;
194 
195   case '2':
196     /* read P2 format: PGM ascii */
197 
198     max = readnum(f);
199     if (max<1) {
200       goto format_error;
201     }
202 
203     for (y=0; y<h; y++) {
204       realheight = y+1;
205       for (x=0; x<w; x++) {
206         b = readnum(f);
207         if (b<0) {
208           goto eof;
209         }
210         BM_UPUT(bm, x, y, b > threshold * max ? 0 : 1);
211       }
212     }
213     break;
214 
215   case '3':
216     /* read P3 format: PPM ascii */
217 
218     max = readnum(f);
219     if (max<1) {
220       goto format_error;
221     }
222 
223     for (y=0; y<h; y++) {
224       realheight = y+1;
225       for (x=0; x<w; x++) {
226 	sum = 0;
227 	for (i=0; i<3; i++) {
228 	  b = readnum(f);
229 	  if (b<0) {
230 	    goto eof;
231 	  }
232 	  sum += b;
233 	}
234         BM_UPUT(bm, x, y, sum > 3 * threshold * max ? 0 : 1);
235       }
236     }
237     break;
238 
239   case '4':
240     /* read P4 format: PBM raw */
241 
242     b = fgetc(f);  /* read single white-space character after height */
243     if (b==EOF) {
244       goto format_error;
245     }
246 
247     bpr = (w+7)/8;
248 
249     for (y=0; y<h; y++) {
250       realheight = y+1;
251       for (i=0; i<bpr; i++) {
252 	b = fgetc(f);
253 	if (b==EOF) {
254 	  goto eof;
255 	}
256 	*bm_index(bm, i*8, y) |= ((potrace_word)b) << (8*(BM_WORDSIZE-1-(i % BM_WORDSIZE)));
257       }
258     }
259     break;
260 
261   case '5':
262     /* read P5 format: PGM raw */
263 
264     max = readnum(f);
265     if (max<1) {
266       goto format_error;
267     }
268 
269     b = fgetc(f);  /* read single white-space character after max */
270     if (b==EOF) {
271       goto format_error;
272     }
273 
274     for (y=0; y<h; y++) {
275       realheight = y+1;
276       for (x=0; x<w; x++) {
277         b = fgetc(f);
278         if (b==EOF)
279           goto eof;
280         if (max>=256) {
281           b <<= 8;
282           b1 = fgetc(f);
283           if (b1==EOF)
284             goto eof;
285           b |= b1;
286         }
287         BM_UPUT(bm, x, y, b > threshold * max ? 0 : 1);
288       }
289     }
290     break;
291 
292   case '6':
293     /* read P6 format: PPM raw */
294 
295     max = readnum(f);
296     if (max<1) {
297       goto format_error;
298     }
299 
300     b = fgetc(f);  /* read single white-space character after max */
301     if (b==EOF) {
302       goto format_error;
303     }
304 
305     for (y=0; y<h; y++) {
306       realheight = y+1;
307       for (x=0; x<w; x++) {
308         sum = 0;
309         for (i=0; i<3; i++) {
310           b = fgetc(f);
311           if (b==EOF) {
312             goto eof;
313 	  }
314           if (max>=256) {
315             b <<= 8;
316             b1 = fgetc(f);
317             if (b1==EOF)
318               goto eof;
319             b |= b1;
320           }
321           sum += b;
322         }
323         BM_UPUT(bm, x, y, sum > 3 * threshold * max ? 0 : 1);
324       }
325     }
326     break;
327   }
328 
329   bm_flip(bm);
330   *bmp = bm;
331   return 0;
332 
333  eof:
334   TRY_STD(bm_resize(bm, realheight));
335   bm_flip(bm);
336   *bmp = bm;
337   return 1;
338 
339  format_error:
340   bm_free(bm);
341   if (magic == '1' || magic == '4') {
342     bm_read_error = "invalid pbm file";
343   } else if (magic == '2' || magic == '5') {
344     bm_read_error = "invalid pgm file";
345   } else {
346     bm_read_error = "invalid ppm file";
347   }
348   return -2;
349 
350  std_error:
351   bm_free(bm);
352   return -1;
353 }
354 
355 /* ---------------------------------------------------------------------- */
356 /* read BMP format */
357 
358 struct bmp_info_s {
359   unsigned int FileSize;
360   unsigned int reserved;
361   unsigned int DataOffset;
362   unsigned int InfoSize;
363   unsigned int w;              /* width */
364   unsigned int h;              /* height */
365   unsigned int Planes;
366   unsigned int bits;           /* bits per sample */
367   unsigned int comp;           /* compression mode */
368   unsigned int ImageSize;
369   unsigned int XpixelsPerM;
370   unsigned int YpixelsPerM;
371   unsigned int ncolors;        /* number of colors in palette */
372   unsigned int ColorsImportant;
373   unsigned int RedMask;
374   unsigned int GreenMask;
375   unsigned int BlueMask;
376   unsigned int AlphaMask;
377   unsigned int ctbits;         /* sample size for color table */
378   int topdown;                 /* top-down mode? */
379 };
380 typedef struct bmp_info_s bmp_info_t;
381 
382 /* auxiliary */
383 
384 static int bmp_count = 0; /* counter for byte padding */
385 static int bmp_pos = 0;   /* counter from start of BMP data */
386 
387 /* read n-byte little-endian integer. Return 1 on EOF or error, else
388    0. Assume n<=4. */
bmp_readint(FILE * f,int n,unsigned int * p)389 static int bmp_readint(FILE *f, int n, unsigned int *p) {
390   int i;
391   unsigned int sum = 0;
392   int b;
393 
394   for (i=0; i<n; i++) {
395     b = fgetc(f);
396     if (b==EOF) {
397       return 1;
398     }
399     sum += (unsigned)b << (8*i);
400   }
401   bmp_count += n;
402   bmp_pos += n;
403   *p = sum;
404   return 0;
405 }
406 
407 /* reset padding boundary */
bmp_pad_reset(void)408 static void bmp_pad_reset(void) {
409   bmp_count = 0;
410 }
411 
412 /* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
413    else 0. */
bmp_pad(FILE * f)414 static int bmp_pad(FILE *f) {
415   int c, i, b;
416 
417   c = (-bmp_count) & 3;
418   for (i=0; i<c; i++) {
419     b = fgetc(f);
420     if (b==EOF) {
421       return 1;
422     }
423   }
424   bmp_pos += c;
425   bmp_count = 0;
426   return 0;
427 }
428 
429 /* forward to the new file position. Return 1 on EOF or error, else 0 */
bmp_forward(FILE * f,int pos)430 static int bmp_forward(FILE *f, int pos) {
431   int b;
432 
433   while (bmp_pos < pos) {
434     b = fgetc(f);
435     if (b==EOF) {
436       return 1;
437     }
438     bmp_pos++;
439     bmp_count++;
440   }
441   return 0;
442 }
443 
444 /* safe colortable access */
445 #define COLTABLE(c) ((c) < bmpinfo.ncolors ? coltable[(c)] : 0)
446 
447 /* read BMP stream after magic number. Return values as for bm_read.
448    We choose to be as permissive as possible, since there are many
449    programs out there which produce BMP. For instance, ppmtobmp can
450    produce codings with anywhere from 1-8 or 24 bits per sample,
451    although most specifications only allow 1,4,8,24,32. We can also
452    read both the old and new OS/2 BMP formats in addition to the
453    Windows BMP format. */
bm_readbody_bmp(FILE * f,double threshold,potrace_bitmap_t ** bmp)454 static int bm_readbody_bmp(FILE *f, double threshold, potrace_bitmap_t **bmp) {
455   bmp_info_t bmpinfo;
456   int *coltable;
457   unsigned int b, c;
458   unsigned int i;
459   potrace_bitmap_t *bm;
460   int mask;
461   unsigned int x, y;
462   int col[2];
463   unsigned int bitbuf;
464   unsigned int n;
465   unsigned int redshift, greenshift, blueshift;
466   int col1[2];
467   int realheight;  /* in case of incomplete file, keeps track of how
468                       many scan lines actually contain data */
469 
470   bm_read_error = NULL;
471   bm = NULL;
472   coltable = NULL;
473 
474   bmp_pos = 2;  /* set file position */
475 
476   /* file header (minus magic number) */
477   TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
478   TRY(bmp_readint(f, 4, &bmpinfo.reserved));
479   TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
480 
481   /* info header */
482   TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
483   if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64
484       || bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124) {
485     /* Windows or new OS/2 format */
486     bmpinfo.ctbits = 32; /* sample size in color table */
487     TRY(bmp_readint(f, 4, &bmpinfo.w));
488     TRY(bmp_readint(f, 4, &bmpinfo.h));
489     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
490     TRY(bmp_readint(f, 2, &bmpinfo.bits));
491     TRY(bmp_readint(f, 4, &bmpinfo.comp));
492     TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
493     TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
494     TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
495     TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
496     TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
497     if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */
498       TRY(bmp_readint(f, 4, &bmpinfo.RedMask));
499       TRY(bmp_readint(f, 4, &bmpinfo.GreenMask));
500       TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
501       TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
502     }
503     if (bmpinfo.w > 0x7fffffff) {
504       goto format_error;
505     }
506     if (bmpinfo.h > 0x7fffffff) {
507       bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
508       bmpinfo.topdown = 1;
509     } else {
510       bmpinfo.topdown = 0;
511     }
512     if (bmpinfo.h > 0x7fffffff) {
513       goto format_error;
514     }
515   } else if (bmpinfo.InfoSize == 12) {
516     /* old OS/2 format */
517     bmpinfo.ctbits = 24; /* sample size in color table */
518     TRY(bmp_readint(f, 2, &bmpinfo.w));
519     TRY(bmp_readint(f, 2, &bmpinfo.h));
520     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
521     TRY(bmp_readint(f, 2, &bmpinfo.bits));
522     bmpinfo.comp = 0;
523     bmpinfo.ncolors = 0;
524     bmpinfo.topdown = 0;
525   } else {
526     goto format_error;
527   }
528 
529   if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) {
530     /* bitfield feature is only understood with V4 and V5 format */
531     goto format_error;
532   }
533 
534   if (bmpinfo.comp > 3 || bmpinfo.bits > 32) {
535     goto format_error;
536   }
537 
538   /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
539   TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
540 
541   if (bmpinfo.Planes != 1) {
542     bm_read_error = "cannot handle bmp planes";
543     goto format_error;  /* can't handle planes */
544   }
545 
546   if (bmpinfo.ncolors == 0 && bmpinfo.bits <= 8) {
547     bmpinfo.ncolors = 1 << bmpinfo.bits;
548   }
549 
550   /* color table, present only if bmpinfo.bits <= 8. */
551   if (bmpinfo.bits <= 8) {
552     coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
553     if (!coltable) {
554       goto std_error;
555     }
556     /* NOTE: since we are reading a bitmap, we can immediately convert
557        the color table entries to bits. */
558     for (i=0; i<bmpinfo.ncolors; i++) {
559       TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
560       c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
561       coltable[i] = (c > 3 * threshold * 255 ? 0 : 1);
562       if (i<2) {
563 	col1[i] = c;
564       }
565     }
566   }
567 
568   /* forward to data */
569   if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
570     TRY(bmp_forward(f, bmpinfo.DataOffset));
571   }
572 
573   /* allocate bitmap */
574   bm = bm_new(bmpinfo.w, bmpinfo.h);
575   if (!bm) {
576     goto std_error;
577   }
578 
579   realheight = 0;
580 
581   switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
582 
583   default:
584     goto format_error;
585     break;
586 
587   case 0x001:  /* monochrome palette */
588     if (col1[0] < col1[1]) { /* make the darker color black */
589       mask = 0xff;
590     } else {
591       mask = 0;
592     }
593 
594     /* raster data */
595     for (y=0; y<bmpinfo.h; y++) {
596       realheight = y+1;
597       bmp_pad_reset();
598       for (i=0; 8*i<bmpinfo.w; i++) {
599 	TRY_EOF(bmp_readint(f, 1, &b));
600 	b ^= mask;
601 	*bm_index(bm, i*8, y) |= ((potrace_word)b) << (8*(BM_WORDSIZE-1-(i % BM_WORDSIZE)));
602       }
603       TRY(bmp_pad(f));
604     }
605     break;
606 
607   case 0x002:  /* 2-bit to 8-bit palettes */
608   case 0x003:
609   case 0x004:
610   case 0x005:
611   case 0x006:
612   case 0x007:
613   case 0x008:
614     for (y=0; y<bmpinfo.h; y++) {
615       realheight = y+1;
616       bmp_pad_reset();
617       bitbuf = 0;  /* bit buffer: bits in buffer are high-aligned */
618       n = 0;       /* number of bits currently in bitbuffer */
619       for (x=0; x<bmpinfo.w; x++) {
620 	if (n < bmpinfo.bits) {
621 	  TRY_EOF(bmp_readint(f, 1, &b));
622 	  bitbuf |= b << (INTBITS - 8 - n);
623 	  n += 8;
624 	}
625 	b = bitbuf >> (INTBITS - bmpinfo.bits);
626 	bitbuf <<= bmpinfo.bits;
627 	n -= bmpinfo.bits;
628 	BM_UPUT(bm, x, y, COLTABLE(b));
629       }
630       TRY(bmp_pad(f));
631     }
632     break;
633 
634   case 0x010:  /* 16-bit encoding */
635     /* can't do this format because it is not well-documented and I
636        don't have any samples */
637     bm_read_error = "cannot handle bmp 16-bit coding";
638     goto format_error;
639     break;
640 
641   case 0x018:  /* 24-bit encoding */
642   case 0x020:  /* 32-bit encoding */
643     for (y=0; y<bmpinfo.h; y++) {
644       realheight = y+1;
645       bmp_pad_reset();
646       for (x=0; x<bmpinfo.w; x++) {
647         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
648 	c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
649         BM_UPUT(bm, x, y, c > 3 * threshold * 255 ? 0 : 1);
650       }
651       TRY(bmp_pad(f));
652     }
653     break;
654 
655   case 0x320:  /* 32-bit encoding with bitfields */
656     if (bmpinfo.RedMask == 0 || bmpinfo.GreenMask == 0 || bmpinfo.BlueMask == 0) {
657       goto format_error;
658     }
659 
660     redshift = lobit(bmpinfo.RedMask);
661     greenshift = lobit(bmpinfo.GreenMask);
662     blueshift = lobit(bmpinfo.BlueMask);
663 
664     for (y=0; y<bmpinfo.h; y++) {
665       realheight = y+1;
666       bmp_pad_reset();
667       for (x=0; x<bmpinfo.w; x++) {
668         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
669 	c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
670         BM_UPUT(bm, x, y, c > 3 * threshold * 255 ? 0 : 1);
671       }
672       TRY(bmp_pad(f));
673     }
674     break;
675 
676   case 0x204:  /* 4-bit runlength compressed encoding (RLE4) */
677     x = 0;
678     y = 0;
679 
680     while (1) {
681       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
682       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
683       if (b>0) {
684 	/* repeat count */
685 	col[0] = COLTABLE((c>>4) & 0xf);
686 	col[1] = COLTABLE(c & 0xf);
687 	for (i=0; i<b && x<bmpinfo.w; i++) {
688 	  if (x>=bmpinfo.w) {
689 	    x=0;
690 	    y++;
691 	  }
692 	  if (y>=bmpinfo.h) {
693 	    break;
694 	  }
695           realheight = y+1;
696 	  BM_UPUT(bm, x, y, col[i&1]);
697 	  x++;
698 	}
699       } else if (c == 0) {
700 	/* end of line */
701 	y++;
702 	x = 0;
703       } else if (c == 1) {
704 	/* end of bitmap */
705 	break;
706       } else if (c == 2) {
707 	/* "delta": skip pixels in x and y directions */
708 	TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
709 	TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
710 	x += b;
711 	y += c;
712       } else {
713 	/* verbatim segment */
714 	for (i=0; i<c; i++) {
715 	  if ((i&1)==0) {
716 	    TRY_EOF(bmp_readint(f, 1, &b));
717 	  }
718 	  if (x>=bmpinfo.w) {
719 	    x=0;
720 	    y++;
721 	  }
722 	  if (y>=bmpinfo.h) {
723 	    break;
724 	  }
725           realheight = y+1;
726 	  BM_PUT(bm, x, y, COLTABLE((b>>(4-4*(i&1))) & 0xf));
727 	  x++;
728 	}
729 	if ((c+1) & 2) {
730 	  /* pad to 16-bit boundary */
731 	  TRY_EOF(bmp_readint(f, 1, &b));
732 	}
733       }
734     }
735     break;
736 
737   case 0x108:  /* 8-bit runlength compressed encoding (RLE8) */
738     x = 0;
739     y = 0;
740     while (1) {
741       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
742       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
743       if (b>0) {
744 	/* repeat count */
745 	for (i=0; i<b; i++) {
746 	  if (x>=bmpinfo.w) {
747 	    x=0;
748 	    y++;
749 	  }
750 	  if (y>=bmpinfo.h) {
751 	    break;
752 	  }
753           realheight = y+1;
754 	  BM_UPUT(bm, x, y, COLTABLE(c));
755 	  x++;
756 	}
757       } else if (c == 0) {
758 	/* end of line */
759 	y++;
760 	x = 0;
761       } else if (c == 1) {
762 	/* end of bitmap */
763 	break;
764       } else if (c == 2) {
765 	/* "delta": skip pixels in x and y directions */
766 	TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
767 	TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
768 	x += b;
769 	y += c;
770       } else {
771 	/* verbatim segment */
772 	for (i=0; i<c; i++) {
773 	  TRY_EOF(bmp_readint(f, 1, &b));
774           if (x>=bmpinfo.w) {
775             x=0;
776             y++;
777           }
778           if (y>=bmpinfo.h) {
779             break;
780           }
781           realheight = y+1;
782 	  BM_PUT(bm, x, y, COLTABLE(b));
783 	  x++;
784 	}
785 	if (c & 1) {
786 	  /* pad input to 16-bit boundary */
787 	  TRY_EOF(bmp_readint(f, 1, &b));
788 	}
789       }
790     }
791     break;
792 
793   } /* switch */
794 
795   /* skip any potential junk after the data section, but don't
796      complain in case EOF is encountered */
797   bmp_forward(f, bmpinfo.FileSize);
798 
799   free(coltable);
800   if (bmpinfo.topdown) {
801     bm_flip(bm);
802   }
803   *bmp = bm;
804   return 0;
805 
806  eof:
807   TRY_STD(bm_resize(bm, realheight));
808   free(coltable);
809   if (bmpinfo.topdown) {
810     bm_flip(bm);
811   }
812   *bmp = bm;
813   return 1;
814 
815  format_error:
816  try_error:
817   free(coltable);
818   bm_free(bm);
819   if (!bm_read_error) {
820     bm_read_error = "invalid bmp file";
821   }
822   return -2;
823 
824  std_error:
825   free(coltable);
826   bm_free(bm);
827   return -1;
828 }
829 
830 /* ---------------------------------------------------------------------- */
831 /* output pbm format */
832 
bm_writepbm(FILE * f,potrace_bitmap_t * bm)833 void bm_writepbm(FILE *f, potrace_bitmap_t *bm) {
834   int w, h, bpr, y, i, c;
835 
836   w = bm->w;
837   h = bm->h;
838 
839   bpr = (w+7)/8;
840 
841   fprintf(f, "P4\n%d %d\n", w, h);
842   for (y=h-1; y>=0; y--) {
843     for (i=0; i<bpr; i++) {
844       c = (*bm_index(bm, i*8, y) >> (8*(BM_WORDSIZE-1-(i % BM_WORDSIZE)))) & 0xff;
845       fputc(c, f);
846     }
847   }
848   return;
849 }
850 
851 /* ---------------------------------------------------------------------- */
852 /* output - for primitive debugging purposes only! */
853 
854 /* print bitmap to screen */
bm_print(FILE * f,potrace_bitmap_t * bm)855 int bm_print(FILE *f, potrace_bitmap_t *bm) {
856   int x, y;
857   int xx, yy;
858   int d;
859   int sw, sh;
860 
861   sw = bm->w < 79 ? bm->w : 79;
862   sh = bm->w < 79 ? bm->h : bm->h*sw*44/(79*bm->w);
863 
864   for (yy=sh-1; yy>=0; yy--) {
865     for (xx=0; xx<sw; xx++) {
866       d=0;
867       for (x=xx*bm->w/sw; x<(xx+1)*bm->w/sw; x++) {
868 	for (y=yy*bm->h/sh; y<(yy+1)*bm->h/sh; y++) {
869 	  if (BM_GET(bm, x, y)) {
870 	    d++;
871 	  }
872 	}
873       }
874       fputc(d ? '*' : ' ', f);
875     }
876     fputc('\n', f);
877   }
878   return 0;
879 }
880 
881