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