Home | History | Annotate | Download | only in jpeg
      1 /*
      2  * rdcolmap.c
      3  *
      4  * Copyright (C) 1994-1996, Thomas G. Lane.
      5  * This file is part of the Independent JPEG Group's software.
      6  * For conditions of distribution and use, see the accompanying README file.
      7  *
      8  * This file implements djpeg's "-map file" switch.  It reads a source image
      9  * and constructs a colormap to be supplied to the JPEG decompressor.
     10  *
     11  * Currently, these file formats are supported for the map file:
     12  *   GIF: the contents of the GIF's global colormap are used.
     13  *   PPM (either text or raw flavor): the entire file is read and
     14  *      each unique pixel value is entered in the map.
     15  * Note that reading a large PPM file will be horrendously slow.
     16  * Typically, a PPM-format map file should contain just one pixel
     17  * of each desired color.  Such a file can be extracted from an
     18  * ordinary image PPM file with ppmtomap(1).
     19  *
     20  * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not
     21  * currently implemented.
     22  */
     23 
     24 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
     25 
     26 #ifdef QUANT_2PASS_SUPPORTED	/* otherwise can't quantize to supplied map */
     27 
     28 /* Portions of this code are based on the PBMPLUS library, which is:
     29 **
     30 ** Copyright (C) 1988 by Jef Poskanzer.
     31 **
     32 ** Permission to use, copy, modify, and distribute this software and its
     33 ** documentation for any purpose and without fee is hereby granted, provided
     34 ** that the above copyright notice appear in all copies and that both that
     35 ** copyright notice and this permission notice appear in supporting
     36 ** documentation.  This software is provided "as is" without express or
     37 ** implied warranty.
     38 */
     39 
     40 
     41 /*
     42  * Add a (potentially) new color to the color map.
     43  */
     44 
     45 LOCAL(void)
     46 add_map_entry (j_decompress_ptr cinfo, int R, int G, int B)
     47 {
     48   JSAMPROW colormap0 = cinfo->colormap[0];
     49   JSAMPROW colormap1 = cinfo->colormap[1];
     50   JSAMPROW colormap2 = cinfo->colormap[2];
     51   int ncolors = cinfo->actual_number_of_colors;
     52   int index;
     53 
     54   /* Check for duplicate color. */
     55   for (index = 0; index < ncolors; index++) {
     56     if (GETJSAMPLE(colormap0[index]) == R &&
     57 	GETJSAMPLE(colormap1[index]) == G &&
     58 	GETJSAMPLE(colormap2[index]) == B)
     59       return;			/* color is already in map */
     60   }
     61 
     62   /* Check for map overflow. */
     63   if (ncolors >= (MAXJSAMPLE+1))
     64     ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1));
     65 
     66   /* OK, add color to map. */
     67   colormap0[ncolors] = (JSAMPLE) R;
     68   colormap1[ncolors] = (JSAMPLE) G;
     69   colormap2[ncolors] = (JSAMPLE) B;
     70   cinfo->actual_number_of_colors++;
     71 }
     72 
     73 
     74 /*
     75  * Extract color map from a GIF file.
     76  */
     77 
     78 LOCAL(void)
     79 read_gif_map (j_decompress_ptr cinfo, FILE * infile)
     80 {
     81   int header[13];
     82   int i, colormaplen;
     83   int R, G, B;
     84 
     85   /* Initial 'G' has already been read by read_color_map */
     86   /* Read the rest of the GIF header and logical screen descriptor */
     87   for (i = 1; i < 13; i++) {
     88     if ((header[i] = getc(infile)) == EOF)
     89       ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
     90   }
     91 
     92   /* Verify GIF Header */
     93   if (header[1] != 'I' || header[2] != 'F')
     94     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
     95 
     96   /* There must be a global color map. */
     97   if ((header[10] & 0x80) == 0)
     98     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
     99 
    100   /* OK, fetch it. */
    101   colormaplen = 2 << (header[10] & 0x07);
    102 
    103   for (i = 0; i < colormaplen; i++) {
    104     R = getc(infile);
    105     G = getc(infile);
    106     B = getc(infile);
    107     if (R == EOF || G == EOF || B == EOF)
    108       ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    109     add_map_entry(cinfo,
    110 		  R << (BITS_IN_JSAMPLE-8),
    111 		  G << (BITS_IN_JSAMPLE-8),
    112 		  B << (BITS_IN_JSAMPLE-8));
    113   }
    114 }
    115 
    116 
    117 /* Support routines for reading PPM */
    118 
    119 
    120 LOCAL(int)
    121 pbm_getc (FILE * infile)
    122 /* Read next char, skipping over any comments */
    123 /* A comment/newline sequence is returned as a newline */
    124 {
    125   register int ch;
    126 
    127   ch = getc(infile);
    128   if (ch == '#') {
    129     do {
    130       ch = getc(infile);
    131     } while (ch != '\n' && ch != EOF);
    132   }
    133   return ch;
    134 }
    135 
    136 
    137 LOCAL(unsigned int)
    138 read_pbm_integer (j_decompress_ptr cinfo, FILE * infile)
    139 /* Read an unsigned decimal integer from the PPM file */
    140 /* Swallows one trailing character after the integer */
    141 /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
    142 /* This should not be a problem in practice. */
    143 {
    144   register int ch;
    145   register unsigned int val;
    146 
    147   /* Skip any leading whitespace */
    148   do {
    149     ch = pbm_getc(infile);
    150     if (ch == EOF)
    151       ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    152   } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
    153 
    154   if (ch < '0' || ch > '9')
    155     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    156 
    157   val = ch - '0';
    158   while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
    159     val *= 10;
    160     val += ch - '0';
    161   }
    162   return val;
    163 }
    164 
    165 
    166 /*
    167  * Extract color map from a PPM file.
    168  */
    169 
    170 LOCAL(void)
    171 read_ppm_map (j_decompress_ptr cinfo, FILE * infile)
    172 {
    173   int c;
    174   unsigned int w, h, maxval, row, col;
    175   int R, G, B;
    176 
    177   /* Initial 'P' has already been read by read_color_map */
    178   c = getc(infile);		/* save format discriminator for a sec */
    179 
    180   /* while we fetch the remaining header info */
    181   w = read_pbm_integer(cinfo, infile);
    182   h = read_pbm_integer(cinfo, infile);
    183   maxval = read_pbm_integer(cinfo, infile);
    184 
    185   if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
    186     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    187 
    188   /* For now, we don't support rescaling from an unusual maxval. */
    189   if (maxval != (unsigned int) MAXJSAMPLE)
    190     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    191 
    192   switch (c) {
    193   case '3':			/* it's a text-format PPM file */
    194     for (row = 0; row < h; row++) {
    195       for (col = 0; col < w; col++) {
    196 	R = read_pbm_integer(cinfo, infile);
    197 	G = read_pbm_integer(cinfo, infile);
    198 	B = read_pbm_integer(cinfo, infile);
    199 	add_map_entry(cinfo, R, G, B);
    200       }
    201     }
    202     break;
    203 
    204   case '6':			/* it's a raw-format PPM file */
    205     for (row = 0; row < h; row++) {
    206       for (col = 0; col < w; col++) {
    207 	R = getc(infile);
    208 	G = getc(infile);
    209 	B = getc(infile);
    210 	if (R == EOF || G == EOF || B == EOF)
    211 	  ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    212 	add_map_entry(cinfo, R, G, B);
    213       }
    214     }
    215     break;
    216 
    217   default:
    218     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    219     break;
    220   }
    221 }
    222 
    223 
    224 /*
    225  * Main entry point from djpeg.c.
    226  *  Input: opened input file (from file name argument on command line).
    227  *  Output: colormap and actual_number_of_colors fields are set in cinfo.
    228  */
    229 
    230 GLOBAL(void)
    231 read_color_map (j_decompress_ptr cinfo, FILE * infile)
    232 {
    233   /* Allocate space for a color map of maximum supported size. */
    234   cinfo->colormap = (*cinfo->mem->alloc_sarray)
    235     ((j_common_ptr) cinfo, JPOOL_IMAGE,
    236      (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);
    237   cinfo->actual_number_of_colors = 0; /* initialize map to empty */
    238 
    239   /* Read first byte to determine file format */
    240   switch (getc(infile)) {
    241   case 'G':
    242     read_gif_map(cinfo, infile);
    243     break;
    244   case 'P':
    245     read_ppm_map(cinfo, infile);
    246     break;
    247   default:
    248     ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
    249     break;
    250   }
    251 }
    252 
    253 #endif /* QUANT_2PASS_SUPPORTED */
    254