Home | History | Annotate | Download | only in libjpeg_turbo
      1 /*
      2  * rdppm.c
      3  *
      4  * Copyright (C) 1991-1997, Thomas G. Lane.
      5  * Modified 2009 by Bill Allombert, Guido Vollbeding.
      6  * This file is part of the Independent JPEG Group's software.
      7  * For conditions of distribution and use, see the accompanying README file.
      8  *
      9  * This file contains routines to read input images in PPM/PGM format.
     10  * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
     11  * The PBMPLUS library is NOT required to compile this software
     12  * (but it is highly useful as a set of PPM image manipulation programs).
     13  *
     14  * These routines may need modification for non-Unix environments or
     15  * specialized applications.  As they stand, they assume input from
     16  * an ordinary stdio stream.  They further assume that reading begins
     17  * at the start of the file; start_input may need work if the
     18  * user interface has already read some data (e.g., to determine that
     19  * the file is indeed PPM format).
     20  */
     21 
     22 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
     23 
     24 #ifdef PPM_SUPPORTED
     25 
     26 
     27 /* Portions of this code are based on the PBMPLUS library, which is:
     28 **
     29 ** Copyright (C) 1988 by Jef Poskanzer.
     30 **
     31 ** Permission to use, copy, modify, and distribute this software and its
     32 ** documentation for any purpose and without fee is hereby granted, provided
     33 ** that the above copyright notice appear in all copies and that both that
     34 ** copyright notice and this permission notice appear in supporting
     35 ** documentation.  This software is provided "as is" without express or
     36 ** implied warranty.
     37 */
     38 
     39 
     40 /* Macros to deal with unsigned chars as efficiently as compiler allows */
     41 
     42 #ifdef HAVE_UNSIGNED_CHAR
     43 typedef unsigned char U_CHAR;
     44 #define UCH(x)	((int) (x))
     45 #else /* !HAVE_UNSIGNED_CHAR */
     46 #ifdef CHAR_IS_UNSIGNED
     47 typedef char U_CHAR;
     48 #define UCH(x)	((int) (x))
     49 #else
     50 typedef char U_CHAR;
     51 #define UCH(x)	((int) (x) & 0xFF)
     52 #endif
     53 #endif /* HAVE_UNSIGNED_CHAR */
     54 
     55 
     56 #define	ReadOK(file,buffer,len)	(JFREAD(file,buffer,len) == ((size_t) (len)))
     57 
     58 
     59 /*
     60  * On most systems, reading individual bytes with getc() is drastically less
     61  * efficient than buffering a row at a time with fread().  On PCs, we must
     62  * allocate the buffer in near data space, because we are assuming small-data
     63  * memory model, wherein fread() can't reach far memory.  If you need to
     64  * process very wide images on a PC, you might have to compile in large-memory
     65  * model, or else replace fread() with a getc() loop --- which will be much
     66  * slower.
     67  */
     68 
     69 
     70 /* Private version of data source object */
     71 
     72 typedef struct {
     73   struct cjpeg_source_struct pub; /* public fields */
     74 
     75   U_CHAR *iobuffer;		/* non-FAR pointer to I/O buffer */
     76   JSAMPROW pixrow;		/* FAR pointer to same */
     77   size_t buffer_width;		/* width of I/O buffer */
     78   JSAMPLE *rescale;		/* => maxval-remapping array, or NULL */
     79 } ppm_source_struct;
     80 
     81 typedef ppm_source_struct * ppm_source_ptr;
     82 
     83 
     84 LOCAL(int)
     85 pbm_getc (FILE * infile)
     86 /* Read next char, skipping over any comments */
     87 /* A comment/newline sequence is returned as a newline */
     88 {
     89   register int ch;
     90 
     91   ch = getc(infile);
     92   if (ch == '#') {
     93     do {
     94       ch = getc(infile);
     95     } while (ch != '\n' && ch != EOF);
     96   }
     97   return ch;
     98 }
     99 
    100 
    101 LOCAL(unsigned int)
    102 read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
    103 /* Read an unsigned decimal integer from the PPM file */
    104 /* Swallows one trailing character after the integer */
    105 /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
    106 /* This should not be a problem in practice. */
    107 {
    108   register int ch;
    109   register unsigned int val;
    110 
    111   /* Skip any leading whitespace */
    112   do {
    113     ch = pbm_getc(infile);
    114     if (ch == EOF)
    115       ERREXIT(cinfo, JERR_INPUT_EOF);
    116   } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
    117 
    118   if (ch < '0' || ch > '9')
    119     ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
    120 
    121   val = ch - '0';
    122   while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
    123     val *= 10;
    124     val += ch - '0';
    125   }
    126   return val;
    127 }
    128 
    129 
    130 /*
    131  * Read one row of pixels.
    132  *
    133  * We provide several different versions depending on input file format.
    134  * In all cases, input is scaled to the size of JSAMPLE.
    135  *
    136  * A really fast path is provided for reading byte/sample raw files with
    137  * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
    138  */
    139 
    140 
    141 METHODDEF(JDIMENSION)
    142 get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    143 /* This version is for reading text-format PGM files with any maxval */
    144 {
    145   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    146   FILE * infile = source->pub.input_file;
    147   register JSAMPROW ptr;
    148   register JSAMPLE *rescale = source->rescale;
    149   JDIMENSION col;
    150 
    151   ptr = source->pub.buffer[0];
    152   for (col = cinfo->image_width; col > 0; col--) {
    153     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
    154   }
    155   return 1;
    156 }
    157 
    158 
    159 METHODDEF(JDIMENSION)
    160 get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    161 /* This version is for reading text-format PPM files with any maxval */
    162 {
    163   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    164   FILE * infile = source->pub.input_file;
    165   register JSAMPROW ptr;
    166   register JSAMPLE *rescale = source->rescale;
    167   JDIMENSION col;
    168 
    169   ptr = source->pub.buffer[0];
    170   for (col = cinfo->image_width; col > 0; col--) {
    171     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
    172     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
    173     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
    174   }
    175   return 1;
    176 }
    177 
    178 
    179 METHODDEF(JDIMENSION)
    180 get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    181 /* This version is for reading raw-byte-format PGM files with any maxval */
    182 {
    183   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    184   register JSAMPROW ptr;
    185   register U_CHAR * bufferptr;
    186   register JSAMPLE *rescale = source->rescale;
    187   JDIMENSION col;
    188 
    189   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    190     ERREXIT(cinfo, JERR_INPUT_EOF);
    191   ptr = source->pub.buffer[0];
    192   bufferptr = source->iobuffer;
    193   for (col = cinfo->image_width; col > 0; col--) {
    194     *ptr++ = rescale[UCH(*bufferptr++)];
    195   }
    196   return 1;
    197 }
    198 
    199 
    200 METHODDEF(JDIMENSION)
    201 get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    202 /* This version is for reading raw-byte-format PPM files with any maxval */
    203 {
    204   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    205   register JSAMPROW ptr;
    206   register U_CHAR * bufferptr;
    207   register JSAMPLE *rescale = source->rescale;
    208   JDIMENSION col;
    209 
    210   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    211     ERREXIT(cinfo, JERR_INPUT_EOF);
    212   ptr = source->pub.buffer[0];
    213   bufferptr = source->iobuffer;
    214   for (col = cinfo->image_width; col > 0; col--) {
    215     *ptr++ = rescale[UCH(*bufferptr++)];
    216     *ptr++ = rescale[UCH(*bufferptr++)];
    217     *ptr++ = rescale[UCH(*bufferptr++)];
    218   }
    219   return 1;
    220 }
    221 
    222 
    223 METHODDEF(JDIMENSION)
    224 get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    225 /* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
    226  * In this case we just read right into the JSAMPLE buffer!
    227  * Note that same code works for PPM and PGM files.
    228  */
    229 {
    230   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    231 
    232   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    233     ERREXIT(cinfo, JERR_INPUT_EOF);
    234   return 1;
    235 }
    236 
    237 
    238 METHODDEF(JDIMENSION)
    239 get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    240 /* This version is for reading raw-word-format PGM files with any maxval */
    241 {
    242   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    243   register JSAMPROW ptr;
    244   register U_CHAR * bufferptr;
    245   register JSAMPLE *rescale = source->rescale;
    246   JDIMENSION col;
    247 
    248   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    249     ERREXIT(cinfo, JERR_INPUT_EOF);
    250   ptr = source->pub.buffer[0];
    251   bufferptr = source->iobuffer;
    252   for (col = cinfo->image_width; col > 0; col--) {
    253     register int temp;
    254     temp  = UCH(*bufferptr++) << 8;
    255     temp |= UCH(*bufferptr++);
    256     *ptr++ = rescale[temp];
    257   }
    258   return 1;
    259 }
    260 
    261 
    262 METHODDEF(JDIMENSION)
    263 get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    264 /* This version is for reading raw-word-format PPM files with any maxval */
    265 {
    266   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    267   register JSAMPROW ptr;
    268   register U_CHAR * bufferptr;
    269   register JSAMPLE *rescale = source->rescale;
    270   JDIMENSION col;
    271 
    272   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    273     ERREXIT(cinfo, JERR_INPUT_EOF);
    274   ptr = source->pub.buffer[0];
    275   bufferptr = source->iobuffer;
    276   for (col = cinfo->image_width; col > 0; col--) {
    277     register int temp;
    278     temp  = UCH(*bufferptr++) << 8;
    279     temp |= UCH(*bufferptr++);
    280     *ptr++ = rescale[temp];
    281     temp  = UCH(*bufferptr++) << 8;
    282     temp |= UCH(*bufferptr++);
    283     *ptr++ = rescale[temp];
    284     temp  = UCH(*bufferptr++) << 8;
    285     temp |= UCH(*bufferptr++);
    286     *ptr++ = rescale[temp];
    287   }
    288   return 1;
    289 }
    290 
    291 
    292 /*
    293  * Read the file header; return image size and component count.
    294  */
    295 
    296 METHODDEF(void)
    297 start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    298 {
    299   ppm_source_ptr source = (ppm_source_ptr) sinfo;
    300   int c;
    301   unsigned int w, h, maxval;
    302   boolean need_iobuffer, use_raw_buffer, need_rescale;
    303 
    304   if (getc(source->pub.input_file) != 'P')
    305     ERREXIT(cinfo, JERR_PPM_NOT);
    306 
    307   c = getc(source->pub.input_file); /* subformat discriminator character */
    308 
    309   /* detect unsupported variants (ie, PBM) before trying to read header */
    310   switch (c) {
    311   case '2':			/* it's a text-format PGM file */
    312   case '3':			/* it's a text-format PPM file */
    313   case '5':			/* it's a raw-format PGM file */
    314   case '6':			/* it's a raw-format PPM file */
    315     break;
    316   default:
    317     ERREXIT(cinfo, JERR_PPM_NOT);
    318     break;
    319   }
    320 
    321   /* fetch the remaining header info */
    322   w = read_pbm_integer(cinfo, source->pub.input_file);
    323   h = read_pbm_integer(cinfo, source->pub.input_file);
    324   maxval = read_pbm_integer(cinfo, source->pub.input_file);
    325 
    326   if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
    327     ERREXIT(cinfo, JERR_PPM_NOT);
    328 
    329   cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
    330   cinfo->image_width = (JDIMENSION) w;
    331   cinfo->image_height = (JDIMENSION) h;
    332 
    333   /* initialize flags to most common settings */
    334   need_iobuffer = TRUE;		/* do we need an I/O buffer? */
    335   use_raw_buffer = FALSE;	/* do we map input buffer onto I/O buffer? */
    336   need_rescale = TRUE;		/* do we need a rescale array? */
    337 
    338   switch (c) {
    339   case '2':			/* it's a text-format PGM file */
    340     cinfo->input_components = 1;
    341     cinfo->in_color_space = JCS_GRAYSCALE;
    342     TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
    343     source->pub.get_pixel_rows = get_text_gray_row;
    344     need_iobuffer = FALSE;
    345     break;
    346 
    347   case '3':			/* it's a text-format PPM file */
    348     cinfo->input_components = 3;
    349     cinfo->in_color_space = JCS_RGB;
    350     TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
    351     source->pub.get_pixel_rows = get_text_rgb_row;
    352     need_iobuffer = FALSE;
    353     break;
    354 
    355   case '5':			/* it's a raw-format PGM file */
    356     cinfo->input_components = 1;
    357     cinfo->in_color_space = JCS_GRAYSCALE;
    358     TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
    359     if (maxval > 255) {
    360       source->pub.get_pixel_rows = get_word_gray_row;
    361     } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
    362       source->pub.get_pixel_rows = get_raw_row;
    363       use_raw_buffer = TRUE;
    364       need_rescale = FALSE;
    365     } else {
    366       source->pub.get_pixel_rows = get_scaled_gray_row;
    367     }
    368     break;
    369 
    370   case '6':			/* it's a raw-format PPM file */
    371     cinfo->input_components = 3;
    372     cinfo->in_color_space = JCS_RGB;
    373     TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
    374     if (maxval > 255) {
    375       source->pub.get_pixel_rows = get_word_rgb_row;
    376     } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
    377       source->pub.get_pixel_rows = get_raw_row;
    378       use_raw_buffer = TRUE;
    379       need_rescale = FALSE;
    380     } else {
    381       source->pub.get_pixel_rows = get_scaled_rgb_row;
    382     }
    383     break;
    384   }
    385 
    386   /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
    387   if (need_iobuffer) {
    388     source->buffer_width = (size_t) w * cinfo->input_components *
    389       ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR)));
    390     source->iobuffer = (U_CHAR *)
    391       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
    392 				  source->buffer_width);
    393   }
    394 
    395   /* Create compressor input buffer. */
    396   if (use_raw_buffer) {
    397     /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
    398     /* Synthesize a JSAMPARRAY pointer structure */
    399     /* Cast here implies near->far pointer conversion on PCs */
    400     source->pixrow = (JSAMPROW) source->iobuffer;
    401     source->pub.buffer = & source->pixrow;
    402     source->pub.buffer_height = 1;
    403   } else {
    404     /* Need to translate anyway, so make a separate sample buffer. */
    405     source->pub.buffer = (*cinfo->mem->alloc_sarray)
    406       ((j_common_ptr) cinfo, JPOOL_IMAGE,
    407        (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
    408     source->pub.buffer_height = 1;
    409   }
    410 
    411   /* Compute the rescaling array if required. */
    412   if (need_rescale) {
    413     INT32 val, half_maxval;
    414 
    415     /* On 16-bit-int machines we have to be careful of maxval = 65535 */
    416     source->rescale = (JSAMPLE *)
    417       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
    418 				  (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
    419     half_maxval = maxval / 2;
    420     for (val = 0; val <= (INT32) maxval; val++) {
    421       /* The multiplication here must be done in 32 bits to avoid overflow */
    422       source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
    423     }
    424   }
    425 }
    426 
    427 
    428 /*
    429  * Finish up at the end of the file.
    430  */
    431 
    432 METHODDEF(void)
    433 finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    434 {
    435   /* no work */
    436 }
    437 
    438 
    439 /*
    440  * The module selection routine for PPM format input.
    441  */
    442 
    443 GLOBAL(cjpeg_source_ptr)
    444 jinit_read_ppm (j_compress_ptr cinfo)
    445 {
    446   ppm_source_ptr source;
    447 
    448   /* Create module interface object */
    449   source = (ppm_source_ptr)
    450       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
    451 				  SIZEOF(ppm_source_struct));
    452   /* Fill in method ptrs, except get_pixel_rows which start_input sets */
    453   source->pub.start_input = start_input_ppm;
    454   source->pub.finish_input = finish_input_ppm;
    455 
    456   return (cjpeg_source_ptr) source;
    457 }
    458 
    459 #endif /* PPM_SUPPORTED */
    460