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