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