home *** CD-ROM | disk | FTP | other *** search
- /*
- * jrdppm.c
- *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This file contains routines to read input images in PPM format.
- * The PBMPLUS library is NOT required to compile this software,
- * but it is highly useful as a set of PPM image manipulation programs.
- *
- * These routines may need modification for non-Unix environments or
- * specialized applications. As they stand, they assume input from
- * an ordinary stdio stream. They further assume that reading begins
- * at the start of the file; input_init may need work if the
- * user interface has already read some data (e.g., to determine that
- * the file is indeed PPM format).
- *
- * These routines are invoked via the methods get_input_row
- * and input_init/term.
- */
-
- #include "jinclude.h"
-
- #ifdef PPM_SUPPORTED
-
-
- /* Portions of this code are based on the PBMPLUS library, which is:
- **
- ** Copyright (C) 1988 by Jef Poskanzer.
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- */
-
-
- /* Macros to deal with unsigned chars as efficiently as compiler allows */
-
- #ifdef HAVE_UNSIGNED_CHAR
- typedef unsigned char U_CHAR;
- #define UCH(x) ((int) (x))
- #else /* !HAVE_UNSIGNED_CHAR */
- #ifdef CHAR_IS_UNSIGNED
- typedef char U_CHAR;
- #define UCH(x) ((int) (x))
- #else
- typedef char U_CHAR;
- #define UCH(x) ((int) (x) & 0xFF)
- #endif
- #endif /* HAVE_UNSIGNED_CHAR */
-
-
- #define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
-
-
- /*
- * On most systems, reading individual bytes with getc() is drastically less
- * efficient than buffering a row at a time with fread(). But we must
- * allocate the row buffer in near data space on PCs, because we are assuming
- * small-data memory model, wherein fread() can't reach far memory. If you
- * need to process very wide images on a PC, you may have to use the getc()
- * approach. In that case, define USE_GETC_INPUT.
- */
-
- #ifndef USE_GETC_INPUT
- static U_CHAR * row_buffer; /* holds 1 pixel row's worth of raw input */
- #endif
-
- static JSAMPLE * rescale; /* => maxval-remapping array, or NULL */
-
-
- LOCAL int
- pbm_getc (FILE * file)
- /* Read next char, skipping over any comments */
- /* A comment/newline sequence is returned as a newline */
- {
- register int ch;
-
- ch = getc(file);
- if (ch == '#') {
- do {
- ch = getc(file);
- } while (ch != '\n' && ch != EOF);
- }
- return ch;
- }
-
-
- LOCAL unsigned int
- read_pbm_integer (compress_info_ptr cinfo)
- /* Read an unsigned decimal integer from the PPM file */
- /* Swallows one trailing character after the integer */
- /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
- /* This should not be a problem in practice. */
- {
- register int ch;
- register unsigned int val;
-
- /* Skip any leading whitespace */
- do {
- ch = pbm_getc(cinfo->input_file);
- if (ch == EOF)
- ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
- } while (ch == ' ' || ch == '\t' || ch == '\n');
-
- if (ch < '0' || ch > '9')
- ERREXIT(cinfo->emethods, "Bogus data in PPM file");
-
- val = ch - '0';
- while ((ch = pbm_getc(cinfo->input_file)) >= '0' && ch <= '9') {
- val *= 10;
- val += ch - '0';
- }
- return val;
- }
-
-
- /*
- * Read one row of pixels.
- *
- * We provide several different versions depending on input file format.
- * In all cases, input is scaled to the size of JSAMPLE; it's possible that
- * when JSAMPLE is 12 bits, this would not really be desirable.
- *
- * Note that a really fast path is provided for reading raw files with
- * maxval = MAXJSAMPLE, which is the normal case (at least for 8-bit JSAMPLEs).
- */
-
-
- METHODDEF void
- get_text_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading text-format PGM files with any maxval */
- {
- register JSAMPROW ptr0;
- register unsigned int val;
- register long col;
-
- ptr0 = pixel_row[0];
- for (col = cinfo->image_width; col > 0; col--) {
- val = read_pbm_integer(cinfo);
- if (rescale != NULL)
- val = rescale[val];
- *ptr0++ = (JSAMPLE) val;
- }
- }
-
-
- METHODDEF void
- get_text_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading text-format PPM files with any maxval */
- {
- register JSAMPROW ptr0, ptr1, ptr2;
- register unsigned int val;
- register long col;
-
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- for (col = cinfo->image_width; col > 0; col--) {
- val = read_pbm_integer(cinfo);
- if (rescale != NULL)
- val = rescale[val];
- *ptr0++ = (JSAMPLE) val;
- val = read_pbm_integer(cinfo);
- if (rescale != NULL)
- val = rescale[val];
- *ptr1++ = (JSAMPLE) val;
- val = read_pbm_integer(cinfo);
- if (rescale != NULL)
- val = rescale[val];
- *ptr2++ = (JSAMPLE) val;
- }
- }
-
-
- #ifdef USE_GETC_INPUT
-
-
- METHODDEF void
- get_scaled_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PGM files with any maxval */
- {
- register FILE * infile = cinfo->input_file;
- register JSAMPROW ptr0;
- register long col;
-
- ptr0 = pixel_row[0];
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = rescale[getc(infile)];
- }
- }
-
-
- METHODDEF void
- get_scaled_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PPM files with any maxval */
- {
- register FILE * infile = cinfo->input_file;
- register JSAMPROW ptr0, ptr1, ptr2;
- register long col;
-
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = rescale[getc(infile)];
- *ptr1++ = rescale[getc(infile)];
- *ptr2++ = rescale[getc(infile)];
- }
- }
-
-
- METHODDEF void
- get_raw_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PGM files with maxval = MAXJSAMPLE */
- {
- register FILE * infile = cinfo->input_file;
- register JSAMPROW ptr0;
- register long col;
-
- ptr0 = pixel_row[0];
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = (JSAMPLE) getc(infile);
- }
- }
-
-
- METHODDEF void
- get_raw_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PPM files with maxval = MAXJSAMPLE */
- {
- register FILE * infile = cinfo->input_file;
- register JSAMPROW ptr0, ptr1, ptr2;
- register long col;
-
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = (JSAMPLE) getc(infile);
- *ptr1++ = (JSAMPLE) getc(infile);
- *ptr2++ = (JSAMPLE) getc(infile);
- }
- }
-
-
- #else /* use row buffering */
-
-
- METHODDEF void
- get_scaled_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PGM files with any maxval */
- {
- register JSAMPROW ptr0;
- register U_CHAR * row_bufferptr;
- register long col;
-
- if (! ReadOK(cinfo->input_file, row_buffer, cinfo->image_width))
- ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
- ptr0 = pixel_row[0];
- row_bufferptr = row_buffer;
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = rescale[UCH(*row_bufferptr++)];
- }
- }
-
-
- METHODDEF void
- get_scaled_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PPM files with any maxval */
- {
- register JSAMPROW ptr0, ptr1, ptr2;
- register U_CHAR * row_bufferptr;
- register long col;
-
- if (! ReadOK(cinfo->input_file, row_buffer, 3 * cinfo->image_width))
- ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- row_bufferptr = row_buffer;
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = rescale[UCH(*row_bufferptr++)];
- *ptr1++ = rescale[UCH(*row_bufferptr++)];
- *ptr2++ = rescale[UCH(*row_bufferptr++)];
- }
- }
-
-
- METHODDEF void
- get_raw_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PGM files with maxval = MAXJSAMPLE */
- {
- register JSAMPROW ptr0;
- register U_CHAR * row_bufferptr;
- register long col;
-
- if (! ReadOK(cinfo->input_file, row_buffer, cinfo->image_width))
- ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
- ptr0 = pixel_row[0];
- row_bufferptr = row_buffer;
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = (JSAMPLE) UCH(*row_bufferptr++);
- }
- }
-
-
- METHODDEF void
- get_raw_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
- /* This version is for reading raw-format PPM files with maxval = MAXJSAMPLE */
- {
- register JSAMPROW ptr0, ptr1, ptr2;
- register U_CHAR * row_bufferptr;
- register long col;
-
- if (! ReadOK(cinfo->input_file, row_buffer, 3 * cinfo->image_width))
- ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
- ptr0 = pixel_row[0];
- ptr1 = pixel_row[1];
- ptr2 = pixel_row[2];
- row_bufferptr = row_buffer;
- for (col = cinfo->image_width; col > 0; col--) {
- *ptr0++ = (JSAMPLE) UCH(*row_bufferptr++);
- *ptr1++ = (JSAMPLE) UCH(*row_bufferptr++);
- *ptr2++ = (JSAMPLE) UCH(*row_bufferptr++);
- }
- }
-
-
- #endif /* USE_GETC_INPUT */
-
-
- /*
- * Read the file header; return image size and component count.
- */
-
- METHODDEF void
- input_init (compress_info_ptr cinfo)
- {
- int c;
- unsigned int w, h, maxval;
-
- if (getc(cinfo->input_file) != 'P')
- ERREXIT(cinfo->emethods, "Not a PPM file");
-
- c = getc(cinfo->input_file); /* save format discriminator for a sec */
-
- w = read_pbm_integer(cinfo); /* while we fetch the header info */
- h = read_pbm_integer(cinfo);
- maxval = read_pbm_integer(cinfo);
-
- if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
- ERREXIT(cinfo->emethods, "Not a PPM file");
-
- switch (c) {
- case '2': /* it's a text-format PGM file */
- cinfo->methods->get_input_row = get_text_gray_row;
- cinfo->input_components = 1;
- cinfo->in_color_space = CS_GRAYSCALE;
- TRACEMS2(cinfo->emethods, 1, "%ux%u text PGM image", w, h);
- break;
-
- case '3': /* it's a text-format PPM file */
- cinfo->methods->get_input_row = get_text_rgb_row;
- cinfo->input_components = 3;
- cinfo->in_color_space = CS_RGB;
- TRACEMS2(cinfo->emethods, 1, "%ux%u text PPM image", w, h);
- break;
-
- case '5': /* it's a raw-format PGM file */
- if (maxval == MAXJSAMPLE)
- cinfo->methods->get_input_row = get_raw_gray_row;
- else
- cinfo->methods->get_input_row = get_scaled_gray_row;
- cinfo->input_components = 1;
- cinfo->in_color_space = CS_GRAYSCALE;
- #ifndef USE_GETC_INPUT
- /* allocate space for row buffer: 1 byte/pixel */
- row_buffer = (U_CHAR *) (*cinfo->emethods->alloc_small)
- ((size_t) (SIZEOF(U_CHAR) * (long) w));
- #endif
- TRACEMS2(cinfo->emethods, 1, "%ux%u PGM image", w, h);
- break;
-
- case '6': /* it's a raw-format PPM file */
- if (maxval == MAXJSAMPLE)
- cinfo->methods->get_input_row = get_raw_rgb_row;
- else
- cinfo->methods->get_input_row = get_scaled_rgb_row;
- cinfo->input_components = 3;
- cinfo->in_color_space = CS_RGB;
- #ifndef USE_GETC_INPUT
- /* allocate space for row buffer: 3 bytes/pixel */
- row_buffer = (U_CHAR *) (*cinfo->emethods->alloc_small)
- ((size_t) (3 * SIZEOF(U_CHAR) * (long) w));
- #endif
- TRACEMS2(cinfo->emethods, 1, "%ux%u PPM image", w, h);
- break;
-
- default:
- ERREXIT(cinfo->emethods, "Not a PPM file");
- break;
- }
-
- /* Compute the rescaling array if necessary */
- /* This saves per-pixel calculation */
- if (maxval == MAXJSAMPLE)
- rescale = NULL; /* no rescaling required */
- else {
- INT32 val, half_maxval;
-
- /* On 16-bit-int machines we have to be careful of maxval = 65535 */
- rescale = (JSAMPLE *) (*cinfo->emethods->alloc_small)
- ((size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
- half_maxval = maxval / 2;
- for (val = 0; val <= (INT32) maxval; val++) {
- /* The multiplication here must be done in 32 bits to avoid overflow */
- rescale[val] = (JSAMPLE) ((val * MAXJSAMPLE + half_maxval) / maxval);
- }
- }
-
- cinfo->image_width = w;
- cinfo->image_height = h;
- cinfo->data_precision = BITS_IN_JSAMPLE;
- }
-
-
- /*
- * Finish up at the end of the file.
- */
-
- METHODDEF void
- input_term (compress_info_ptr cinfo)
- {
- /* no work (we let free_all release the workspace) */
- }
-
-
- /*
- * The method selection routine for PPM format input.
- * Note that this must be called by the user interface before calling
- * jpeg_compress. If multiple input formats are supported, the
- * user interface is responsible for discovering the file format and
- * calling the appropriate method selection routine.
- */
-
- GLOBAL void
- jselrppm (compress_info_ptr cinfo)
- {
- cinfo->methods->input_init = input_init;
- /* cinfo->methods->get_input_row is set by input_init */
- cinfo->methods->input_term = input_term;
- }
-
- #endif /* PPM_SUPPORTED */
-