greymap.c
Go to the documentation of this file.
00001 /* Copyright (C) 2001-2007 Peter Selinger.
00002    This file is part of Potrace. It is free software and it is covered
00003    by the GNU General Public License. See the file COPYING for details. */
00004 
00005 /* $Id: greymap.c 147 2007-04-09 00:44:09Z selinger $ */
00006 
00007 /* Routines for manipulating greymaps, including reading pgm files. We
00008    only deal with greymaps of depth 8 bits. */
00009 
00010 #include <stdlib.h>
00011 #include <errno.h>
00012 #include <string.h>
00013 #include <math.h>
00014 
00015 #include "greymap.h"
00016 
00017 #define INTBITS (8*sizeof(int))
00018 
00019 #define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
00020 
00021 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
00022 static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
00023 
00024 /* ---------------------------------------------------------------------- */
00025 /* basic greymap routines */
00026 
00027 /* return new un-initialized greymap. NULL with errno on error */
00028 
00029 greymap_t *gm_new(int w, int h) {
00030   greymap_t *gm;
00031   int errno_save;
00032 
00033   gm = (greymap_t *) malloc(sizeof(greymap_t));
00034   if (!gm) {
00035     return NULL;
00036   }
00037   gm->w = w;
00038   gm->h = h;
00039   gm->map = (signed short int *) malloc(w*h*sizeof(signed short int));
00040   if (!gm->map) {
00041     errno_save = errno;
00042     free(gm);
00043     errno = errno_save;
00044     return NULL;
00045   }
00046   return gm;
00047 }
00048 
00049 /* free the given greymap */
00050 void gm_free(greymap_t *gm) {
00051   if (gm) {
00052     free(gm->map);
00053   }
00054   free(gm);
00055 }
00056 
00057 /* duplicate the given greymap. Return NULL on error with errno set. */
00058 greymap_t *gm_dup(greymap_t *gm) {
00059   greymap_t *gm1 = gm_new(gm->w, gm->h);
00060   if (!gm1) {
00061     return NULL;
00062   }
00063   memcpy(gm1->map, gm->map, gm->w*gm->h*2);
00064   return gm1;
00065 }
00066 
00067 /* clear the given greymap to color b. */
00068 void gm_clear(greymap_t *gm, int b) {
00069   int i;
00070 
00071   if (b==0) {
00072     memset(gm->map, 0, gm->w*gm->h*2);
00073   } else {
00074     for (i=0; i<gm->w*gm->h; i++) {
00075       gm->map[i] = b;
00076     }
00077   }    
00078 }
00079 
00080 /* ---------------------------------------------------------------------- */
00081 /* routines for reading pnm streams */
00082 
00083 /* read next character after whitespace and comments. Return EOF on
00084    end of file or error. */
00085 static int fgetc_ws(FILE *f) {
00086   int c;
00087 
00088   while (1) {
00089     c = fgetc(f);
00090     if (c=='#') {
00091       while (1) {
00092         c = fgetc(f);
00093         if (c=='\n' || c==EOF) {
00094           break;
00095         }
00096       }
00097     }
00098     /* space, tab, line feed, carriage return, form-feed */
00099     if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
00100       return c;
00101     }
00102   }
00103 }
00104 
00105 /* skip whitespace and comments, then read a non-negative decimal
00106    number from a stream. Return -1 on EOF. Tolerate other errors (skip
00107    bad characters). Do not the read any characters following the
00108    number (put next character back into the stream) */
00109 
00110 static int readnum(FILE *f) {
00111   int c;
00112   int acc;
00113 
00114   /* skip whitespace and comments */
00115   while (1) {
00116     c = fgetc_ws(f);
00117     if (c==EOF) {
00118       return -1;
00119     }
00120     if (c>='0' && c<='9') {
00121       break;
00122     }
00123   }
00124 
00125   /* first digit is already in c */
00126   acc = c-'0';
00127   while (1) {
00128     c = fgetc(f);
00129     if (c==EOF) {
00130       break;
00131     }
00132     if (c<'0' || c>'9') {
00133       ungetc(c, f);
00134       break;
00135     }
00136     acc *= 10;
00137     acc += c-'0';
00138   }
00139   return acc;
00140 }
00141 
00142 /* similar to readnum, but read only a single 0 or 1, and do not read
00143    any characters after it. */
00144 
00145 static int readbit(FILE *f) {
00146   int c;
00147 
00148   /* skip whitespace and comments */
00149   while (1) {
00150     c = fgetc_ws(f);
00151     if (c==EOF) {
00152       return -1;
00153     }
00154     if (c>='0' && c<='1') {
00155       break;
00156     }
00157   }
00158 
00159   return c-'0';
00160 }
00161 
00162 /* ---------------------------------------------------------------------- */
00163 
00164 /* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
00165    convert the output to a greymap. Return greymap in *gmp. Return 0
00166    on success, -1 on error with errno set, -2 on bad file format (with
00167    error message in gm_read_error), and 1 on premature end of file, -3
00168    on empty file (including files with only whitespace and comments),
00169    -4 if wrong magic number. If the return value is >=0, *gmp is
00170    valid. */
00171 
00172 char *gm_read_error = NULL;
00173 
00174 int gm_read(FILE *f, greymap_t **gmp) {
00175   int magic[2];
00176 
00177   /* read magic number. We ignore whitespace and comments before the
00178      magic, for the benefit of concatenated files in P1-P3 format.
00179      Multiple P1-P3 images in a single file are not formally allowed
00180      by the PNM standard, but there is no harm in being lenient. */
00181 
00182   magic[0] = fgetc_ws(f);
00183   if (magic[0] == EOF) {
00184     /* files which contain only comments and whitespace count as "empty" */
00185     return -3;
00186   } 
00187   magic[1] = fgetc(f);
00188   if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
00189     return gm_readbody_pnm(f, gmp, magic[1]);
00190   }
00191   if (magic[0] == 'B' && magic[1] == 'M') {
00192     return gm_readbody_bmp(f, gmp);
00193   }
00194   return -4;
00195 }
00196 
00197 /* ---------------------------------------------------------------------- */
00198 /* read PNM format */
00199 
00200 /* read PNM stream after magic number. Return values as for gm_read */
00201 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
00202   greymap_t *gm;
00203   int x, y, i, j, b, b1, sum;
00204   int bpr; /* bytes per row (as opposed to 4*gm->c) */
00205   int w, h, max;
00206 
00207   gm = NULL;
00208 
00209   w = readnum(f);
00210   if (w<0) {
00211     goto format_error;
00212   }
00213 
00214   h = readnum(f);
00215   if (h<0) {
00216     goto format_error;
00217   }
00218 
00219   /* allocate greymap */
00220   gm = gm_new(w, h);
00221   if (!gm) {
00222     return -1;
00223   }
00224 
00225   /* zero it out */
00226   gm_clear(gm, 0);
00227 
00228   switch (magic) {
00229   default: 
00230     /* not reached */
00231     goto format_error;  
00232 
00233   case '1':
00234     /* read P1 format: PBM ascii */
00235     
00236     for (y=h-1; y>=0; y--) {
00237       for (x=0; x<w; x++) {
00238         b = readbit(f);
00239         if (b<0) {
00240           goto eof;
00241         }
00242         GM_UPUT(gm, x, y, b ? 0 : 255);
00243       }
00244     }
00245     break;
00246 
00247   case '2':
00248     /* read P2 format: PGM ascii */
00249     
00250     max = readnum(f);
00251     if (max<1) {
00252       goto format_error;
00253     }
00254     
00255     for (y=h-1; y>=0; y--) {
00256       for (x=0; x<w; x++) {
00257         b = readnum(f);
00258         if (b<0) {
00259           goto eof;
00260         }
00261         GM_UPUT(gm, x, y, b*255/max);
00262       }
00263     }
00264     break;
00265 
00266   case '3':
00267     /* read P3 format: PPM ascii */
00268     
00269     max = readnum(f);
00270     if (max<1) {
00271       goto format_error;
00272     }
00273     
00274     for (y=h-1; y>=0; y--) {
00275       for (x=0; x<w; x++) {
00276         sum = 0;
00277         for (i=0; i<3; i++) {
00278           b = readnum(f);
00279           if (b<0) {
00280             goto eof;
00281           }
00282           sum += b;
00283         }
00284         GM_UPUT(gm, x, y, sum*(255/3)/max);
00285       }
00286     }
00287     break;
00288 
00289   case '4':
00290     /* read P4 format: PBM raw */
00291 
00292     b = fgetc(f);  /* read single white-space character after height */
00293     if (b==EOF) {
00294       goto format_error;
00295     }
00296 
00297     bpr = (w+7)/8;
00298 
00299     for (y=h-1; y>=0; y--) {
00300       for (i=0; i<bpr; i++) {
00301         b = fgetc(f);
00302         if (b==EOF) {
00303           goto eof;
00304         }
00305         for (j=0; j<8; j++) {
00306           GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
00307         }
00308       }
00309     }
00310     break;
00311 
00312   case '5':
00313     /* read P5 format: PGM raw */
00314 
00315     max = readnum(f);
00316     if (max<1) {
00317       goto format_error;
00318     }
00319 
00320     b = fgetc(f);  /* read single white-space character after max */
00321     if (b==EOF) {
00322       goto format_error;
00323     }
00324 
00325     for (y=h-1; y>=0; y--) {
00326       for (x=0; x<w; x++) {
00327         b = fgetc(f);
00328         if (b==EOF)
00329           goto eof;
00330         if (max>=256) {
00331           b <<= 8;
00332           b1 = fgetc(f);
00333           if (b1==EOF)
00334             goto eof;
00335           b |= b1;
00336         }
00337         GM_UPUT(gm, x, y, b*255/max);
00338       }
00339     }
00340     break;
00341 
00342   case '6':
00343     /* read P6 format: PPM raw */
00344 
00345     max = readnum(f);
00346     if (max<1) {
00347       goto format_error;
00348     }
00349 
00350     b = fgetc(f);  /* read single white-space character after max */
00351     if (b==EOF) {
00352       goto format_error;
00353     }
00354 
00355     for (y=h-1; y>=0; y--) {
00356       for (x=0; x<w; x++) {
00357         sum = 0;
00358         for (i=0; i<3; i++) {
00359           b = fgetc(f);
00360           if (b==EOF) {
00361             goto eof;
00362           }
00363           if (max>=256) {
00364             b <<= 8;
00365             b1 = fgetc(f);
00366             if (b1==EOF)
00367               goto eof;
00368             b |= b1;
00369           }
00370           sum += b;
00371         }
00372         GM_UPUT(gm, x, y, sum*(255/3)/max);
00373       }
00374     }
00375     break;
00376   }
00377 
00378   *gmp = gm;
00379   return 0;
00380 
00381  eof:
00382   *gmp = gm;
00383   return 1;
00384 
00385  format_error:
00386   gm_free(gm);
00387   if (magic == '1' || magic == '4') {
00388     gm_read_error = "invalid pbm file";
00389   } else if (magic == '2' || magic == '5') {
00390     gm_read_error = "invalid pgm file";
00391   } else {
00392     gm_read_error = "invalid ppm file";
00393   }
00394   return -2;
00395 }
00396 
00397 /* ---------------------------------------------------------------------- */
00398 /* read BMP format */
00399 
00400 struct bmp_info_s {
00401   unsigned int FileSize;
00402   unsigned int reserved;
00403   unsigned int DataOffset;
00404   unsigned int InfoSize;
00405   unsigned int w;              /* width */
00406   unsigned int h;              /* height */
00407   unsigned int Planes;
00408   unsigned int bits;           /* bits per sample */
00409   unsigned int comp;           /* compression mode */
00410   unsigned int ImageSize;
00411   unsigned int XpixelsPerM;
00412   unsigned int YpixelsPerM;
00413   unsigned int ncolors;        /* number of colors in palette */
00414   unsigned int ColorsImportant;
00415   unsigned int ctbits;         /* sample size for color table */
00416 };
00417 typedef struct bmp_info_s bmp_info_t;
00418 
00419 /* auxiliary */
00420 
00421 static int bmp_count = 0; /* counter for byte padding */
00422 static int bmp_pos = 0;   /* counter from start of BMP data */
00423 
00424 /* read n-byte little-endian integer. Return 1 on EOF or error, else
00425    0. Assume n<=4. */
00426 static int bmp_readint(FILE *f, int n, unsigned int *p) {
00427   int i;
00428   unsigned int sum = 0;
00429   int b;
00430 
00431   for (i=0; i<n; i++) {
00432     b = fgetc(f);
00433     if (b==EOF) {
00434       return 1;
00435     }
00436     sum += b << (8*i);
00437   }
00438   bmp_count += n;
00439   bmp_pos += n;
00440   *p = sum;
00441   return 0;
00442 }
00443 
00444 /* reset padding boundary */
00445 static void bmp_pad_reset(void) {
00446   bmp_count = 0;
00447 }
00448 
00449 /* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
00450    else 0. */
00451 static int bmp_pad(FILE *f) {
00452   int c, i, b;
00453 
00454   c = (-bmp_count) & 3;
00455   for (i=0; i<c; i++) {
00456     b = fgetc(f);
00457     if (b==EOF) {
00458       return 1;
00459     }
00460   }
00461   bmp_pos += c;
00462   bmp_count = 0;
00463   return 0;
00464 }
00465   
00466 /* forward to the new file position. Return 1 on EOF or error, else 0 */
00467 static int bmp_forward(FILE *f, int pos) {
00468   int b;
00469 
00470   while (bmp_pos < pos) {
00471     b = fgetc(f);
00472     if (b==EOF) {
00473       return 1;
00474     }
00475     bmp_pos++;
00476     bmp_count++;
00477   }
00478   return 0;
00479 }
00480 
00481 #define TRY(x) if (x) goto try_error
00482 #define TRY_EOF(x) if (x) goto eof
00483 
00484 /* read BMP stream after magic number. Return values as for gm_read.
00485    We choose to be as permissive as possible, since there are many
00486    programs out there which produce BMP. For instance, ppmtobmp can
00487    produce codings with anywhere from 1-8 or 24 bits per sample,
00488    although most specifications only allow 1,4,8,24,32. We can also
00489    read both the old and new OS/2 BMP formats in addition to the
00490    Windows BMP format. */
00491 static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
00492   bmp_info_t bmpinfo;
00493   int *coltable;
00494   unsigned int b, c;
00495   unsigned int i, j;
00496   greymap_t *gm;
00497   unsigned int x, y;
00498   int col[2];
00499   unsigned int bitbuf;
00500   unsigned int n;
00501 
00502   gm_read_error = NULL;
00503   gm = NULL;
00504   coltable = NULL;
00505 
00506   bmp_pos = 2;  /* set file position */
00507 
00508   /* file header (minus magic number) */
00509   TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
00510   TRY(bmp_readint(f, 4, &bmpinfo.reserved));
00511   TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
00512 
00513   /* info header */
00514   TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
00515   if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64) {
00516     /* Windows or new OS/2 format */
00517     bmpinfo.ctbits = 32; /* sample size in color table */
00518     TRY(bmp_readint(f, 4, &bmpinfo.w));
00519     TRY(bmp_readint(f, 4, &bmpinfo.h));
00520     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
00521     TRY(bmp_readint(f, 2, &bmpinfo.bits));
00522     TRY(bmp_readint(f, 4, &bmpinfo.comp));
00523     TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
00524     TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
00525     TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
00526     TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
00527     TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
00528   } else if (bmpinfo.InfoSize == 12) {
00529     /* old OS/2 format */
00530     bmpinfo.ctbits = 24; /* sample size in color table */
00531     TRY(bmp_readint(f, 2, &bmpinfo.w));
00532     TRY(bmp_readint(f, 2, &bmpinfo.h));
00533     TRY(bmp_readint(f, 2, &bmpinfo.Planes));
00534     TRY(bmp_readint(f, 2, &bmpinfo.bits));
00535     bmpinfo.comp = 0;
00536     bmpinfo.ncolors = 0;
00537   } else {
00538     goto format_error;
00539   }
00540 
00541   /* forward to color table (i.e., if bmpinfo.InfoSize == 64) */
00542   TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
00543 
00544   if (bmpinfo.Planes != 1) {
00545     gm_read_error = "cannot handle bmp planes";
00546     goto format_error;  /* can't handle planes */
00547   }
00548   
00549   if (bmpinfo.ncolors == 0) {
00550     bmpinfo.ncolors = 1 << bmpinfo.bits;
00551   }
00552 
00553   /* color table, present only if bmpinfo.bits <= 8. */
00554   if (bmpinfo.bits <= 8) {
00555     coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int));
00556     if (!coltable) {
00557       goto std_error;
00558     }
00559     /* NOTE: since we are reading a greymap, we can immediately convert
00560        the color table entries to grey values. */
00561     for (i=0; i<bmpinfo.ncolors; i++) {
00562       TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
00563       c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
00564       coltable[i] = c/3;
00565     }
00566   }
00567 
00568   /* forward to data */
00569   if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
00570     TRY(bmp_forward(f, bmpinfo.DataOffset));
00571   }
00572 
00573   /* allocate greymap */
00574   gm = gm_new(bmpinfo.w, bmpinfo.h);
00575   if (!gm) {
00576     goto std_error;
00577   }
00578   
00579   /* zero it out */
00580   gm_clear(gm, 0);
00581 
00582   switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
00583     
00584   default:
00585     goto format_error;
00586     break;
00587     
00588   case 0x001:  /* monochrome palette */
00589 
00590     /* raster data */
00591     for (y=0; y<bmpinfo.h; y++) {
00592       bmp_pad_reset();
00593       for (i=0; 8*i<bmpinfo.w; i++) {
00594         TRY_EOF(bmp_readint(f, 1, &b));
00595         for (j=0; j<8; j++) {
00596           GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? coltable[1] : coltable[0]);
00597         }
00598       }
00599       TRY(bmp_pad(f));
00600     }
00601     break;
00602    
00603   case 0x002:  /* 2-bit to 8-bit palettes */
00604   case 0x003: 
00605   case 0x004: 
00606   case 0x005: 
00607   case 0x006: 
00608   case 0x007: 
00609   case 0x008:
00610     for (y=0; y<bmpinfo.h; y++) {
00611       bmp_pad_reset();
00612       bitbuf = 0;  /* bit buffer: bits in buffer are high-aligned */
00613       n = 0;       /* number of bits currently in bitbuffer */
00614       for (x=0; x<bmpinfo.w; x++) {
00615         if (n < bmpinfo.bits) {
00616           TRY_EOF(bmp_readint(f, 1, &b));
00617           bitbuf |= b << (INTBITS - 8 - n);
00618           n += 8;
00619         }
00620         b = bitbuf >> (INTBITS - bmpinfo.bits);
00621         bitbuf <<= bmpinfo.bits;
00622         n -= bmpinfo.bits;
00623         GM_UPUT(gm, x, y, coltable[b]);
00624       }
00625       TRY(bmp_pad(f));
00626     }
00627     break;
00628 
00629   case 0x010:  /* 16-bit encoding */
00630     /* can't do this format because it is not well-documented and I
00631        don't have any samples */
00632     gm_read_error = "cannot handle bmp 16-bit coding";
00633     goto format_error;
00634     break;
00635 
00636   case 0x018:  /* 24-bit encoding */
00637   case 0x020:  /* 32-bit encoding */
00638     for (y=0; y<bmpinfo.h; y++) {
00639       bmp_pad_reset();
00640       for (x=0; x<bmpinfo.w; x++) {
00641         TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
00642         c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
00643         GM_UPUT(gm, x, y, c/3);
00644       }
00645       TRY(bmp_pad(f));
00646     }
00647     break;
00648 
00649   case 0x204:  /* 4-bit runlength compressed encoding (RLE4) */
00650     x = 0;
00651     y = 0;
00652     while (1) {
00653       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
00654       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
00655       if (b>0) {
00656         /* repeat count */
00657         col[0] = coltable[(c>>4) & 0xf];
00658         col[1] = coltable[c & 0xf];
00659         for (i=0; i<b && x<bmpinfo.w; i++) {
00660           if (x>=bmpinfo.w) {
00661             x=0;
00662             y++;
00663           }
00664           if (y>=bmpinfo.h) {
00665             break;
00666           }
00667           GM_UPUT(gm, x, y, col[i&1]);
00668           x++;
00669         }
00670       } else if (c == 0) {
00671         /* end of line */
00672         y++;
00673         x = 0;
00674       } else if (c == 1) {
00675         /* end of greymap */
00676         break;
00677       } else if (c == 2) {
00678         /* "delta": skip pixels in x and y directions */
00679         TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
00680         TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
00681         x += b;
00682         y += c;
00683       } else {
00684         /* verbatim segment */
00685         for (i=0; i<c; i++) {
00686           if ((i&1)==0) {
00687             TRY_EOF(bmp_readint(f, 1, &b));
00688           }
00689           if (x>=bmpinfo.w) {
00690             x=0;
00691             y++;
00692           }
00693           if (y>=bmpinfo.h) {
00694             break;
00695           }
00696           GM_PUT(gm, x, y, coltable[(b>>(4-4*(i&1))) & 0xf]);
00697           x++;
00698         }
00699         if ((c+1) & 2) {
00700           /* pad to 16-bit boundary */
00701           TRY_EOF(bmp_readint(f, 1, &b));
00702         }
00703       }
00704     }
00705     break;
00706 
00707   case 0x108:  /* 8-bit runlength compressed encoding (RLE8) */
00708     x = 0;
00709     y = 0;
00710     while (1) {
00711       TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
00712       TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
00713       if (b>0) {
00714         /* repeat count */
00715         for (i=0; i<b; i++) {
00716           if (x>=bmpinfo.w) {
00717             x=0;
00718             y++;
00719           }
00720           if (y>=bmpinfo.h) {
00721             break;
00722           }
00723           GM_UPUT(gm, x, y, coltable[c]);
00724           x++;
00725         }
00726       } else if (c == 0) {
00727         /* end of line */
00728         y++;
00729         x = 0;
00730       } else if (c == 1) {
00731         /* end of greymap */
00732         break;
00733       } else if (c == 2) {
00734         /* "delta": skip pixels in x and y directions */
00735         TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
00736         TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
00737         x += b;
00738         y += c;
00739       } else {
00740         /* verbatim segment */
00741         for (i=0; i<c; i++) {
00742           TRY_EOF(bmp_readint(f, 1, &b));
00743           if (x>=bmpinfo.w) {
00744             x=0;
00745             y++;
00746           }
00747           if (y>=bmpinfo.h) {
00748             break;
00749           }
00750           GM_PUT(gm, x, y, coltable[b]);
00751           x++;
00752         }
00753         if (c & 1) {
00754           /* pad input to 16-bit boundary */
00755           TRY_EOF(bmp_readint(f, 1, &b));
00756         }
00757       }
00758     }
00759     break;
00760 
00761   } /* switch */
00762 
00763   /* skip any potential junk after the data section, but don't
00764      complain in case EOF is encountered */
00765   bmp_forward(f, bmpinfo.FileSize);
00766 
00767   free(coltable);
00768   *gmp = gm;
00769   return 0;
00770 
00771  eof:
00772   free(coltable);
00773   *gmp = gm;
00774   return 1;
00775 
00776  format_error:
00777  try_error:
00778   free(coltable);
00779   free(gm);
00780   if (!gm_read_error) {
00781     gm_read_error = "invalid bmp file";
00782   }
00783   return -2;
00784 
00785  std_error:
00786   free(coltable);
00787   free(gm);
00788   return -1;
00789 }
00790 
00791 /* ---------------------------------------------------------------------- */
00792 
00793 /* write a pgm stream, either P2 or (if raw != 0) P5 format. Include
00794    one-line comment if non-NULL. Mode determines how out-of-range
00795    color values are converted. Gamma is the desired gamma correction,
00796    if any (set to 2.2 if the image is to look optimal on a CRT monitor,
00797    2.8 for LCD). Set to 1.0 for no gamma correction */
00798 
00799 int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma) {
00800   int x, y, v;
00801   int gammatable[256];
00802   
00803   /* prepare gamma correction lookup table */
00804   if (gamma != 1.0) {
00805     gammatable[0] = 0;
00806     for (v=1; v<256; v++) {
00807       gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
00808     }
00809   } else {
00810     for (v=0; v<256; v++) {
00811       gammatable[v] = v;
00812     }
00813   }  
00814 
00815   fprintf(f, raw ? "P5\n" : "P2\n");
00816   if (comment && *comment) {
00817     fprintf(f, "# %s\n", comment);
00818   }
00819   fprintf(f, "%d %d 255\n", gm->w, gm->h);
00820   for (y=gm->h-1; y>=0; y--) {
00821     for (x=0; x<gm->w; x++) {
00822       v = GM_UGET(gm, x, y);
00823       if (mode == GM_MODE_NONZERO) {
00824         if (v > 255) {
00825           v = 510 - v;
00826         }
00827         if (v < 0) {
00828           v = 0;
00829         }
00830       } else if (mode == GM_MODE_ODD) {
00831         v = mod(v, 510);
00832         if (v > 255) {
00833           v = 510 - v;
00834         }
00835       } else if (mode == GM_MODE_POSITIVE) {
00836         if (v < 0) {
00837           v = 0;
00838         } else if (v > 255) {
00839           v = 255;
00840         }
00841       } else if (mode == GM_MODE_NEGATIVE) {
00842         v = 510 - v;
00843         if (v < 0) {
00844           v = 0;
00845         } else if (v > 255) {
00846           v = 255;
00847         }
00848       }
00849       v = gammatable[v];
00850       
00851       if (raw) {
00852         fputc(v, f);
00853       } else {
00854         fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
00855       }   
00856     }
00857   }
00858   return 0;
00859 }
00860 
00861 /* ---------------------------------------------------------------------- */
00862 /* output - for primitive debugging purposes only! */
00863 
00864 /* print greymap to screen */
00865 int gm_print(FILE *f, greymap_t *gm) {
00866   int x, y;
00867   int xx, yy;
00868   int d, t;
00869   int sw, sh;
00870 
00871   sw = gm->w < 79 ? gm->w : 79;
00872   sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
00873 
00874   for (yy=sh-1; yy>=0; yy--) {
00875     for (xx=0; xx<sw; xx++) {
00876       d=0;
00877       t=0;
00878       for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
00879         for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
00880           d += GM_GET(gm, x, y);
00881           t += 256;
00882         }
00883       }
00884       fputc("*#=- "[5*d/t], f);  /* what a cute trick :) */
00885     }
00886     fputc('\n', f);
00887   }
00888   return 0;
00889 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


portrait_painter
Author(s): Niklas Meinzer, Ina Baumgarten
autogenerated on Wed Dec 26 2012 16:00:43