File indexing completed on 2024-12-22 04:04:12

0001 /* Copyright (C) 2001-2019 Peter Selinger.
0002    This file is part of Potrace. It is free software and it is covered
0003    by the GNU General Public License. See the file COPYING for details. */
0004 
0005 
0006 /* Routines for manipulating greymaps, including reading pgm files. We
0007    only deal with greymaps of depth 8 bits. */
0008 
0009 #ifdef HAVE_CONFIG_H
0010 #include <config.h>
0011 #endif
0012 
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <math.h>
0016 #include <errno.h>
0017 #include <stddef.h>
0018 #ifdef HAVE_INTTYPES_H
0019 #include <inttypes.h>
0020 #endif
0021 
0022 #include "greymap.h"
0023 #include "bitops.h"
0024 
0025 #define INTBITS (8*sizeof(int))
0026 
0027 #define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
0028 
0029 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
0030 static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
0031 
0032 #define TRY(x) if (x) goto try_error
0033 #define TRY_EOF(x) if (x) goto eof
0034 #define TRY_STD(x) if (x) goto std_error
0035 
0036 /* ---------------------------------------------------------------------- */
0037 /* basic greymap routines */
0038 
0039 /* calculate the size, in bytes, required for the data area of a
0040    greymap of the given dy and h. Assume h >= 0. Return -1 if the size
0041    does not fit into the ptrdiff_t type. */
0042 static inline ptrdiff_t getsize(int dy, int h) {
0043   ptrdiff_t size;
0044 
0045   if (dy < 0) {
0046     dy = -dy;
0047   }
0048   
0049   size = (ptrdiff_t)dy * (ptrdiff_t)h * (ptrdiff_t)GM_SAMPLESIZE;
0050 
0051   /* check for overflow error */
0052   if (size < 0 || (h != 0 && dy != 0 && size / h / dy != GM_SAMPLESIZE)) {
0053     return -1;
0054   }
0055 
0056   return size;
0057 }
0058 
0059 /* return the size, in bytes, of the data area of the greymap. Return
0060    -1 if the size does not fit into the ptrdiff_t type; however, this
0061    cannot happen if the bitmap is well-formed, i.e., if created with
0062    gm_new or gm_dup. */
0063 static inline ptrdiff_t gm_size(const greymap_t *gm) {
0064   return getsize(gm->dy, gm->h);
0065 }
0066 
0067 
0068 
0069 /* return new greymap initialized to 0. NULL with errno on error.
0070    Assumes w, h >= 0. */
0071 greymap_t *gm_new(int w, int h) {
0072   greymap_t *gm;
0073   int dy = w;
0074   ptrdiff_t size;
0075 
0076   size = getsize(dy, h);
0077   if (size < 0) {
0078     errno = ENOMEM;
0079     return NULL;
0080   }
0081   if (size == 0) {
0082     size = GM_SAMPLESIZE; /* make sure calloc() doesn't return NULL */
0083   }
0084   
0085   gm = (greymap_t *) malloc(sizeof(greymap_t));
0086   if (!gm) {
0087     return NULL;
0088   }
0089   gm->w = w;
0090   gm->h = h;
0091   gm->dy = dy;
0092   gm->base = (gm_sample_t *) calloc(1, size);
0093   if (!gm->base) {
0094     free(gm);
0095     return NULL;
0096   }
0097   gm->map = gm->base;
0098   return gm;
0099 }
0100 
0101 /* free the given greymap */
0102 void gm_free(greymap_t *gm) {
0103   if (gm) {
0104     free(gm->base);
0105   }
0106   free(gm);
0107 }
0108 
0109 /* duplicate the given greymap. Return NULL on error with errno set. */
0110 greymap_t *gm_dup(greymap_t *gm) {
0111   greymap_t *gm1 = gm_new(gm->w, gm->h);
0112   int y;
0113   
0114   if (!gm1) {
0115     return NULL;
0116   }
0117   for (y=0; y<gm->h; y++) {
0118     memcpy(gm_scanline(gm1, y), gm_scanline(gm, y), (size_t)gm1->dy * GM_SAMPLESIZE);
0119   }
0120   return gm1;
0121 }
0122 
0123 /* clear the given greymap to color b. */
0124 void gm_clear(greymap_t *gm, int b) {
0125   ptrdiff_t size = gm_size(gm);
0126   int x, y;
0127   
0128   if (b==0) {
0129     memset(gm->base, 0, size);
0130   } else {
0131     for (y=0; y<gm->h; y++) {
0132       for (x=0; x<gm->w; x++) {
0133         GM_UPUT(gm, x, y, b);
0134       }
0135     }
0136   }
0137 }
0138 
0139 /* turn the given greymap upside down. This does not move the pixel
0140    data or change the base address. */
0141 static inline void gm_flip(greymap_t *gm) {
0142   int dy = gm->dy;
0143 
0144   if (gm->h == 0 || gm->h == 1) {
0145     return;
0146   }
0147   
0148   gm->map = gm_scanline(gm, gm->h - 1);
0149   gm->dy = -dy;
0150 }
0151 
0152 /* resize the greymap to the given new height. The pixel data remains
0153    bottom-aligned (truncated at the top) when dy >= 0 and top-aligned
0154    (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on
0155    error with errno set. If the new height is <= the old one, no error
0156    should occur. If the new height is larger, the additional pixel
0157    data is *not* initialized. */
0158 static inline int gm_resize(greymap_t *gm, int h) {
0159   int dy = gm->dy;
0160   ptrdiff_t newsize;
0161   gm_sample_t *newbase;
0162 
0163   if (dy < 0) {
0164     gm_flip(gm);
0165   }
0166   
0167   newsize = getsize(dy, h);
0168   if (newsize < 0) {
0169     errno = ENOMEM;
0170     goto error;
0171   }
0172   if (newsize == 0) {
0173     newsize = GM_SAMPLESIZE; /* make sure realloc() doesn't return NULL */
0174   }
0175   
0176   newbase = (gm_sample_t *)realloc(gm->base, newsize);
0177   if (newbase == NULL) {
0178     goto error;
0179   }
0180   gm->base = newbase;
0181   gm->map = newbase;
0182   gm->h = h;
0183 
0184   if (dy < 0) {
0185     gm_flip(gm);
0186   }
0187   return 0;
0188   
0189  error:
0190   if (dy < 0) {
0191     gm_flip(gm);
0192   }
0193   return 1;  
0194 }
0195 
0196 
0197 /* ---------------------------------------------------------------------- */
0198 /* routines for reading pnm streams */
0199 
0200 /* read next character after whitespace and comments. Return EOF on
0201    end of file or error. */
0202 static int fgetc_ws(FILE *f) {
0203   int c;
0204 
0205   while (1) {
0206     c = fgetc(f);
0207     if (c=='#') {
0208       while (1) {
0209     c = fgetc(f);
0210     if (c=='\n' || c==EOF) {
0211       break;
0212     }
0213       }
0214     }
0215     /* space, tab, line feed, carriage return, form-feed */
0216     if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
0217       return c;
0218     }
0219   }
0220 }
0221 
0222 /* skip whitespace and comments, then read a non-negative decimal
0223    number from a stream. Return -1 on EOF. Tolerate other errors (skip
0224    bad characters). Do not the read any characters following the
0225    number (put next character back into the stream) */
0226 
0227 static int readnum(FILE *f) {
0228   int c;
0229   uint64_t acc;
0230 
0231   /* skip whitespace and comments */
0232   while (1) {
0233     c = fgetc_ws(f);
0234     if (c==EOF) {
0235       return -1;
0236     }
0237     if (c>='0' && c<='9') {
0238       break;
0239     }
0240   }
0241 
0242   /* first digit is already in c */
0243   acc = c-'0';
0244   while (1) {
0245     c = fgetc(f);
0246     if (c==EOF) {
0247       break;
0248     }
0249     if (c<'0' || c>'9') {
0250       ungetc(c, f);
0251       break;
0252     }
0253     acc *= 10;
0254     acc += c-'0';
0255     if (acc > 0x7fffffff) {
0256       return -1;
0257     }
0258   }
0259   return acc;
0260 }
0261 
0262 /* similar to readnum, but read only a single 0 or 1, and do not read
0263    any characters after it. */
0264 
0265 static int readbit(FILE *f) {
0266   int c;
0267 
0268   /* skip whitespace and comments */
0269   while (1) {
0270     c = fgetc_ws(f);
0271     if (c==EOF) {
0272       return -1;
0273     }
0274     if (c>='0' && c<='1') {
0275       break;
0276     }
0277   }
0278 
0279   return c-'0';
0280 }
0281 
0282 /* ---------------------------------------------------------------------- */
0283 
0284 /* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
0285    convert the output to a greymap. Return greymap in *gmp. Return 0
0286    on success, -1 on error with errno set, -2 on bad file format (with
0287    error message in gm_read_error), and 1 on premature end of file, -3
0288    on empty file (including files with only whitespace and comments),
0289    -4 if wrong magic number. If the return value is >=0, *gmp is
0290    valid. */
0291 
0292 const char *gm_read_error = NULL;
0293 
0294 int gm_read(FILE *f, greymap_t **gmp) {
0295   int magic[2];
0296 
0297   /* read magic number. We ignore whitespace and comments before the
0298      magic, for the benefit of concatenated files in P1-P3 format.
0299      Multiple P1-P3 images in a single file are not formally allowed
0300      by the PNM standard, but there is no harm in being lenient. */
0301 
0302   magic[0] = fgetc_ws(f);
0303   if (magic[0] == EOF) {
0304     /* files which contain only comments and whitespace count as "empty" */
0305     return -3;
0306   } 
0307   magic[1] = fgetc(f);
0308   if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
0309     return gm_readbody_pnm(f, gmp, magic[1]);
0310   }
0311   if (magic[0] == 'B' && magic[1] == 'M') {
0312     return gm_readbody_bmp(f, gmp);
0313   }
0314   return -4;
0315 }
0316 
0317 /* ---------------------------------------------------------------------- */
0318 /* read PNM format */
0319 
0320 /* read PNM stream after magic number. Return values as for gm_read */
0321 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
0322   greymap_t *gm;
0323   int x, y, i, j, b, b1, sum;
0324   int bpr; /* bytes per row (as opposed to 4*gm->c) */
0325   int w, h, max;
0326   int realheight;  /* in case of incomplete file, keeps track of how
0327                       many scan lines actually contain data */
0328   
0329   gm = NULL;
0330 
0331   w = readnum(f);
0332   if (w<0) {
0333     goto format_error;
0334   }
0335 
0336   h = readnum(f);
0337   if (h<0) {
0338     goto format_error;
0339   }
0340 
0341   /* allocate greymap */
0342   gm = gm_new(w, h);
0343   if (!gm) {
0344     goto std_error;
0345   }
0346 
0347   realheight = 0;
0348 
0349   switch (magic) {
0350   default: 
0351     /* not reached */
0352     goto format_error;  
0353 
0354   case '1':
0355     /* read P1 format: PBM ascii */
0356     
0357     for (y=0; y<h; y++) {
0358       realheight = y+1;
0359       for (x=0; x<w; x++) {
0360     b = readbit(f);
0361     if (b<0) {
0362       goto eof;
0363     }
0364     GM_UPUT(gm, x, y, b ? 0 : 255);
0365       }
0366     }
0367     break;
0368 
0369   case '2':
0370     /* read P2 format: PGM ascii */
0371     
0372     max = readnum(f);
0373     if (max<1) {
0374       goto format_error;
0375     }
0376     
0377     for (y=0; y<h; y++) {
0378       realheight = y+1;
0379       for (x=0; x<w; x++) {
0380         b = readnum(f);
0381         if (b<0) {
0382           goto eof;
0383         }
0384         GM_UPUT(gm, x, y, b*255/max);
0385       }
0386     }
0387     break;
0388 
0389   case '3':
0390     /* read P3 format: PPM ascii */
0391     
0392     max = readnum(f);
0393     if (max<1) {
0394       goto format_error;
0395     }
0396     
0397     for (y=0; y<h; y++) {
0398       realheight = y+1;
0399       for (x=0; x<w; x++) {
0400     sum = 0;
0401     for (i=0; i<3; i++) {
0402       b = readnum(f);
0403       if (b<0) {
0404         goto eof;
0405       }
0406       sum += b;
0407     }
0408         GM_UPUT(gm, x, y, sum*(255/3)/max);
0409       }
0410     }
0411     break;
0412 
0413   case '4':
0414     /* read P4 format: PBM raw */
0415 
0416     b = fgetc(f);  /* read single white-space character after height */
0417     if (b==EOF) {
0418       goto format_error;
0419     }
0420 
0421     bpr = (w+7)/8;
0422 
0423     for (y=0; y<h; y++) {
0424       realheight = y+1;
0425       for (i=0; i<bpr; i++) {
0426     b = fgetc(f);
0427     if (b==EOF) {
0428       goto eof;
0429     }
0430     for (j=0; j<8; j++) {
0431       GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
0432     }
0433       }
0434     }
0435     break;
0436 
0437   case '5':
0438     /* read P5 format: PGM raw */
0439 
0440     max = readnum(f);
0441     if (max<1) {
0442       goto format_error;
0443     }
0444 
0445     b = fgetc(f);  /* read single white-space character after max */
0446     if (b==EOF) {
0447       goto format_error;
0448     }
0449 
0450     for (y=0; y<h; y++) {
0451       realheight = y+1;
0452       for (x=0; x<w; x++) {
0453         b = fgetc(f);
0454         if (b==EOF)
0455           goto eof;
0456         if (max>=256) {
0457           b <<= 8;
0458           b1 = fgetc(f);
0459           if (b1==EOF)
0460             goto eof;
0461           b |= b1;
0462         }
0463         GM_UPUT(gm, x, y, b*255/max);
0464       }
0465     }
0466     break;
0467 
0468   case '6':
0469     /* read P6 format: PPM raw */
0470 
0471     max = readnum(f);
0472     if (max<1) {
0473       goto format_error;
0474     }
0475 
0476     b = fgetc(f);  /* read single white-space character after max */
0477     if (b==EOF) {
0478       goto format_error;
0479     }
0480 
0481     for (y=0; y<h; y++) {
0482       realheight = y+1;
0483       for (x=0; x<w; x++) {
0484         sum = 0;
0485         for (i=0; i<3; i++) {
0486           b = fgetc(f);
0487           if (b==EOF) {
0488             goto eof;
0489       }
0490           if (max>=256) {
0491             b <<= 8;
0492             b1 = fgetc(f);
0493             if (b1==EOF)
0494               goto eof;
0495             b |= b1;
0496           }
0497           sum += b;
0498         }
0499         GM_UPUT(gm, x, y, sum*(255/3)/max);
0500       }
0501     }
0502     break;
0503   }
0504 
0505   gm_flip(gm);
0506   *gmp = gm;
0507   return 0;
0508 
0509  eof:
0510   TRY_STD(gm_resize(gm, realheight));
0511   gm_flip(gm);
0512   *gmp = gm;
0513   return 1;
0514 
0515  format_error:
0516   gm_free(gm);
0517   if (magic == '1' || magic == '4') {
0518     gm_read_error = "invalid pbm file";
0519   } else if (magic == '2' || magic == '5') {
0520     gm_read_error = "invalid pgm file";
0521   } else {
0522     gm_read_error = "invalid ppm file";
0523   }
0524   return -2;
0525 
0526  std_error:
0527   gm_free(gm);
0528   return -1;
0529 }
0530 
0531 /* ---------------------------------------------------------------------- */
0532 /* read BMP format */
0533 
0534 struct bmp_info_s {
0535   unsigned int FileSize;
0536   unsigned int reserved;
0537   unsigned int DataOffset;
0538   unsigned int InfoSize;
0539   unsigned int w;              /* width */
0540   unsigned int h;              /* height */
0541   unsigned int Planes;
0542   unsigned int bits;           /* bits per sample */
0543   unsigned int comp;           /* compression mode */
0544   unsigned int ImageSize;
0545   unsigned int XpixelsPerM;
0546   unsigned int YpixelsPerM;
0547   unsigned int ncolors;        /* number of colors in palette */
0548   unsigned int ColorsImportant;
0549   unsigned int RedMask;
0550   unsigned int GreenMask;
0551   unsigned int BlueMask;
0552   unsigned int AlphaMask;
0553   unsigned int ctbits;         /* sample size for color table */
0554   int topdown;                 /* top-down mode? */
0555 };
0556 typedef struct bmp_info_s bmp_info_t;
0557 
0558 /* auxiliary */
0559 
0560 static int bmp_count = 0; /* counter for byte padding */
0561 static int bmp_pos = 0;   /* counter from start of BMP data */
0562 
0563 /* read n-byte little-endian integer. Return 1 on EOF or error, else
0564    0. Assume n<=4. */
0565 static int bmp_readint(FILE *f, int n, unsigned int *p) {
0566   int i;
0567   unsigned int sum = 0;
0568   int b;
0569 
0570   for (i=0; i<n; i++) {
0571     b = fgetc(f);
0572     if (b==EOF) {
0573       return 1;
0574     }
0575     sum += (unsigned)b << (8*i);
0576   }
0577   bmp_count += n;
0578   bmp_pos += n;
0579   *p = sum;
0580   return 0;
0581 }
0582 
0583 /* reset padding boundary */
0584 static void bmp_pad_reset(void) {
0585   bmp_count = 0;
0586 }
0587 
0588 /* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
0589    else 0. */
0590 static int bmp_pad(FILE *f) {
0591   int c, i, b;
0592 
0593   c = (-bmp_count) & 3;
0594   for (i=0; i<c; i++) {
0595     b = fgetc(f);
0596     if (b==EOF) {
0597       return 1;
0598     }
0599   }
0600   bmp_pos += c;
0601   bmp_count = 0;
0602   return 0;
0603 }
0604   
0605 /* forward to the new file position. Return 1 on EOF or error, else 0 */
0606 static int bmp_forward(FILE *f, int pos) {
0607   int b;
0608 
0609   while (bmp_pos < pos) {
0610     b = fgetc(f);
0611     if (b==EOF) {
0612       return 1;
0613     }
0614     bmp_pos++;
0615     bmp_count++;
0616   }
0617   return 0;
0618 }
0619 
0620 /* safe colortable access */
0621 #define COLTABLE(c) ((c) < bmpinfo.ncolors ? coltable[(c)] : 0)
0622 
0623 /* read BMP stream after magic number. Return values as for gm_read.
0624    We choose to be as permissive as possible, since there are many
0625    programs out there which produce BMP. For instance, ppmtobmp can
0626    produce codings with anywhere from 1-8 or 24 bits per sample,
0627    although most specifications only allow 1,4,8,24,32. We can also
0628    read both the old and new OS/2 BMP formats in addition to the
0629    Windows BMP format. */
0630 static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
0631   bmp_info_t bmpinfo;
0632   int *coltable;
0633   unsigned int b, c;
0634   unsigned int i, j;
0635   greymap_t *gm;
0636   unsigned int x, y;
0637   int col[2];
0638   unsigned int bitbuf;
0639   unsigned int n;
0640   unsigned int redshift, greenshift, blueshift;
0641   int realheight;  /* in case of incomplete file, keeps track of how
0642                       many scan lines actually contain data */
0643 
0644   gm_read_error = NULL;
0645   gm = NULL;
0646   coltable = NULL;
0647 
0648   bmp_pos = 2;  /* set file position */
0649 
0650   /* file header (minus magic number) */
0651   TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
0652   TRY(bmp_readint(f, 4, &bmpinfo.reserved));
0653   TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
0654 
0655   /* info header */
0656   TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
0657   if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64
0658       || bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124) {
0659     /* Windows or new OS/2 format */
0660     bmpinfo.ctbits = 32; /* sample size in color table */
0661     TRY(bmp_readint(f, 4, &bmpinfo.w));
0662     TRY(bmp_readint(f, 4, &bmpinfo.h));
0663     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
0664     TRY(bmp_readint(f, 2, &bmpinfo.bits));
0665     TRY(bmp_readint(f, 4, &bmpinfo.comp));
0666     TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
0667     TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
0668     TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
0669     TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
0670     TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
0671     if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */
0672       TRY(bmp_readint(f, 4, &bmpinfo.RedMask));
0673       TRY(bmp_readint(f, 4, &bmpinfo.GreenMask));
0674       TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
0675       TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
0676     }
0677     if (bmpinfo.w > 0x7fffffff) {
0678       goto format_error;
0679     }
0680     if (bmpinfo.h > 0x7fffffff) {
0681       bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
0682       bmpinfo.topdown = 1;
0683     } else {
0684       bmpinfo.topdown = 0;
0685     }
0686     if (bmpinfo.h > 0x7fffffff) {
0687       goto format_error;
0688     }
0689   } else if (bmpinfo.InfoSize == 12) {
0690     /* old OS/2 format */
0691     bmpinfo.ctbits = 24; /* sample size in color table */
0692     TRY(bmp_readint(f, 2, &bmpinfo.w));
0693     TRY(bmp_readint(f, 2, &bmpinfo.h));
0694     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
0695     TRY(bmp_readint(f, 2, &bmpinfo.bits));
0696     bmpinfo.comp = 0;
0697     bmpinfo.ncolors = 0;
0698     bmpinfo.topdown = 0;
0699   } else {
0700     goto format_error;
0701   }
0702 
0703   if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) {
0704     /* bitfield feature is only understood with V4 and V5 format */
0705     goto format_error;
0706   }
0707 
0708   if (bmpinfo.comp > 3 || bmpinfo.bits > 32) {
0709     goto format_error;
0710   }
0711   
0712   /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
0713   TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
0714 
0715   if (bmpinfo.Planes != 1) {
0716     gm_read_error = "cannot handle bmp planes";
0717     goto format_error;  /* can't handle planes */
0718   }
0719   
0720   if (bmpinfo.ncolors == 0 && bmpinfo.bits <= 8) {
0721     bmpinfo.ncolors = 1 << bmpinfo.bits;
0722   }
0723 
0724   /* color table, present only if bmpinfo.bits <= 8. */
0725   if (bmpinfo.bits <= 8) {
0726     coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
0727     if (!coltable) {
0728       goto std_error;
0729     }
0730     /* NOTE: since we are reading a greymap, we can immediately convert
0731        the color table entries to grey values. */
0732     for (i=0; i<bmpinfo.ncolors; i++) {
0733       TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
0734       c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
0735       coltable[i] = c/3;
0736     }
0737   }
0738 
0739   /* forward to data */
0740   if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
0741     TRY(bmp_forward(f, bmpinfo.DataOffset));
0742   }
0743 
0744   /* allocate greymap */
0745   gm = gm_new(bmpinfo.w, bmpinfo.h);
0746   if (!gm) {
0747     goto std_error;
0748   }
0749 
0750   realheight = 0;
0751   
0752   switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
0753     
0754   default:
0755     goto format_error;
0756     break;
0757     
0758   case 0x001:  /* monochrome palette */
0759 
0760     /* raster data */
0761     for (y=0; y<bmpinfo.h; y++) {
0762       realheight = y+1;
0763       bmp_pad_reset();
0764       for (i=0; 8*i<bmpinfo.w; i++) {
0765     TRY_EOF(bmp_readint(f, 1, &b));
0766     for (j=0; j<8; j++) {
0767       GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? COLTABLE(1) : COLTABLE(0));
0768     }
0769       }
0770       TRY(bmp_pad(f));
0771     }
0772     break;
0773    
0774   case 0x002:  /* 2-bit to 8-bit palettes */
0775   case 0x003: 
0776   case 0x004: 
0777   case 0x005: 
0778   case 0x006: 
0779   case 0x007: 
0780   case 0x008:
0781     for (y=0; y<bmpinfo.h; y++) {
0782       realheight = y+1;
0783       bmp_pad_reset();
0784       bitbuf = 0;  /* bit buffer: bits in buffer are high-aligned */
0785       n = 0;       /* number of bits currently in bitbuffer */
0786       for (x=0; x<bmpinfo.w; x++) {
0787     if (n < bmpinfo.bits) {
0788       TRY_EOF(bmp_readint(f, 1, &b));
0789       bitbuf |= b << (INTBITS - 8 - n);
0790       n += 8;
0791     }
0792     b = bitbuf >> (INTBITS - bmpinfo.bits);
0793     bitbuf <<= bmpinfo.bits;
0794     n -= bmpinfo.bits;
0795     GM_UPUT(gm, x, y, COLTABLE(b));
0796       }
0797       TRY(bmp_pad(f));
0798     }
0799     break;
0800 
0801   case 0x010:  /* 16-bit encoding */
0802     /* can't do this format because it is not well-documented and I
0803        don't have any samples */
0804     gm_read_error = "cannot handle bmp 16-bit coding";
0805     goto format_error;
0806     break;
0807 
0808   case 0x018:  /* 24-bit encoding */
0809   case 0x020:  /* 32-bit encoding */
0810     for (y=0; y<bmpinfo.h; y++) {
0811       realheight = y+1;
0812       bmp_pad_reset();
0813       for (x=0; x<bmpinfo.w; x++) {
0814         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
0815     c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
0816         GM_UPUT(gm, x, y, c/3);
0817       }
0818       TRY(bmp_pad(f));
0819     }
0820     break;
0821 
0822   case 0x320:  /* 32-bit encoding with bitfields */
0823     redshift = lobit(bmpinfo.RedMask);
0824     greenshift = lobit(bmpinfo.GreenMask);
0825     blueshift = lobit(bmpinfo.BlueMask);
0826 
0827     for (y=0; y<bmpinfo.h; y++) {
0828       realheight = y+1;
0829       bmp_pad_reset();
0830       for (x=0; x<bmpinfo.w; x++) {
0831         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
0832     c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
0833         GM_UPUT(gm, x, y, c/3);
0834       }
0835       TRY(bmp_pad(f));
0836     }
0837     break;
0838 
0839   case 0x204:  /* 4-bit runlength compressed encoding (RLE4) */
0840     x = 0;
0841     y = 0;
0842     while (1) {
0843       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
0844       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
0845       if (b>0) {
0846     /* repeat count */
0847     col[0] = COLTABLE((c>>4) & 0xf);
0848     col[1] = COLTABLE(c & 0xf);
0849     for (i=0; i<b && x<bmpinfo.w; i++) {
0850       if (x>=bmpinfo.w) {
0851         x=0;
0852         y++;
0853       }
0854       if (x>=bmpinfo.w || y>=bmpinfo.h) {
0855         break;
0856       }
0857           realheight = y+1;
0858       GM_PUT(gm, x, y, col[i&1]);
0859       x++;
0860     }
0861       } else if (c == 0) {
0862     /* end of line */
0863     y++;
0864     x = 0;
0865       } else if (c == 1) {
0866     /* end of greymap */
0867     break;
0868       } else if (c == 2) {
0869     /* "delta": skip pixels in x and y directions */
0870     TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
0871     TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
0872     x += b;
0873     y += c;
0874       } else {
0875     /* verbatim segment */
0876     for (i=0; i<c; i++) {
0877       if ((i&1)==0) {
0878         TRY_EOF(bmp_readint(f, 1, &b));
0879       }
0880       if (x>=bmpinfo.w) {
0881         x=0;
0882         y++;
0883       }
0884       if (x>=bmpinfo.w || y>=bmpinfo.h) {
0885         break;
0886       }
0887           realheight = y+1;
0888       GM_PUT(gm, x, y, COLTABLE((b>>(4-4*(i&1))) & 0xf));
0889       x++;
0890     }
0891     if ((c+1) & 2) {
0892       /* pad to 16-bit boundary */
0893       TRY_EOF(bmp_readint(f, 1, &b));
0894     }
0895       }
0896     }
0897     break;
0898 
0899   case 0x108:  /* 8-bit runlength compressed encoding (RLE8) */
0900     x = 0;
0901     y = 0;
0902     while (1) {
0903       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
0904       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
0905       if (b>0) {
0906     /* repeat count */
0907     for (i=0; i<b; i++) {
0908       if (x>=bmpinfo.w) {
0909         x=0;
0910         y++;
0911       }
0912       if (x>=bmpinfo.w || y>=bmpinfo.h) {
0913         break;
0914       }
0915           realheight = y+1;
0916       GM_PUT(gm, x, y, COLTABLE(c));
0917       x++;
0918     }
0919       } else if (c == 0) {
0920     /* end of line */
0921     y++;
0922     x = 0;
0923       } else if (c == 1) {
0924     /* end of greymap */
0925     break;
0926       } else if (c == 2) {
0927     /* "delta": skip pixels in x and y directions */
0928     TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
0929     TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
0930     x += b;
0931     y += c;
0932       } else {
0933     /* verbatim segment */
0934     for (i=0; i<c; i++) {
0935       TRY_EOF(bmp_readint(f, 1, &b));
0936           if (x>=bmpinfo.w) {
0937             x=0;
0938             y++;
0939           }
0940       if (x>=bmpinfo.w || y>=bmpinfo.h) {
0941             break;
0942           }
0943           realheight = y+1;
0944       GM_PUT(gm, x, y, COLTABLE(b));
0945       x++;
0946     }
0947     if (c & 1) {
0948       /* pad input to 16-bit boundary */
0949       TRY_EOF(bmp_readint(f, 1, &b));
0950     }
0951       }
0952     }
0953     break;
0954 
0955   } /* switch */
0956 
0957   /* skip any potential junk after the data section, but don't
0958      complain in case EOF is encountered */
0959   bmp_forward(f, bmpinfo.FileSize);
0960 
0961   free(coltable);
0962   if (bmpinfo.topdown) {
0963     gm_flip(gm);
0964   }
0965   *gmp = gm;
0966   return 0;
0967 
0968  eof:
0969   TRY_STD(gm_resize(gm, realheight));
0970   free(coltable);
0971   if (bmpinfo.topdown) {
0972     gm_flip(gm);
0973   }
0974   *gmp = gm;
0975   return 1;
0976 
0977  format_error:
0978  try_error:
0979   free(coltable);
0980   gm_free(gm);
0981   if (!gm_read_error) {
0982     gm_read_error = "invalid bmp file";
0983   }
0984   return -2;
0985 
0986  std_error:
0987   free(coltable);
0988   gm_free(gm);
0989   return -1;
0990 }
0991 
0992 /* ---------------------------------------------------------------------- */
0993 
0994 /* write a pgm stream, either P2 or (if raw != 0) P5 format. Include
0995    one-line comment if non-NULL. Mode determines how out-of-range
0996    color values are converted. Gamma is the desired gamma correction,
0997    if any (set to 2.2 if the image is to look optimal on a CRT monitor,
0998    2.8 for LCD). Set to 1.0 for no gamma correction */
0999 
1000 int gm_writepgm(FILE *f, greymap_t *gm, const char *comment, int raw, int mode, double gamma) {
1001   int x, y, v;
1002   int gammatable[256];
1003   
1004   /* prepare gamma correction lookup table */
1005   if (gamma != 1.0) {
1006     gammatable[0] = 0;
1007     for (v=1; v<256; v++) {
1008       gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
1009     }
1010   } else {
1011     for (v=0; v<256; v++) {
1012       gammatable[v] = v;
1013     }
1014   }  
1015 
1016   fprintf(f, raw ? "P5\n" : "P2\n");
1017   if (comment && *comment) {
1018     fprintf(f, "# %s\n", comment);
1019   }
1020   fprintf(f, "%d %d 255\n", gm->w, gm->h);
1021   for (y=gm->h-1; y>=0; y--) {
1022     for (x=0; x<gm->w; x++) {
1023       v = GM_UGET(gm, x, y);
1024       if (mode == GM_MODE_NONZERO) {
1025     if (v > 255) {
1026       v = 510 - v;
1027     }
1028     if (v < 0) {
1029       v = 0;
1030     }
1031       } else if (mode == GM_MODE_ODD) {
1032     v = mod(v, 510);
1033     if (v > 255) {
1034       v = 510 - v;
1035     }
1036       } else if (mode == GM_MODE_POSITIVE) {
1037     if (v < 0) {
1038       v = 0;
1039     } else if (v > 255) {
1040       v = 255;
1041     }
1042       } else if (mode == GM_MODE_NEGATIVE) {
1043     v = 510 - v;
1044     if (v < 0) {
1045       v = 0;
1046     } else if (v > 255) {
1047       v = 255;
1048     }
1049       }
1050       v = gammatable[v];
1051       
1052       if (raw) {
1053     fputc(v, f);
1054       } else {
1055     fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
1056       }   
1057     }
1058   }
1059   return 0;
1060 }
1061 
1062 /* ---------------------------------------------------------------------- */
1063 /* output - for primitive debugging purposes only! */
1064 
1065 /* print greymap to screen */
1066 int gm_print(FILE *f, greymap_t *gm) {
1067   int x, y;
1068   int xx, yy;
1069   int d, t;
1070   int sw, sh;
1071 
1072   sw = gm->w < 79 ? gm->w : 79;
1073   sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
1074 
1075   for (yy=sh-1; yy>=0; yy--) {
1076     for (xx=0; xx<sw; xx++) {
1077       d=0;
1078       t=0;
1079       for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
1080     for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
1081       d += GM_GET(gm, x, y);
1082       t += 256;
1083     }
1084       }
1085       fputc("*#=- "[5*d/t], f);  /* what a cute trick :) */
1086     }
1087     fputc('\n', f);
1088   }
1089   return 0;
1090 }