| /* |
| * 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 |
| |
| |
| static JSAMPLE * rescale; /* => maxval-remapping array, or NULL */ |
| |
| |
| /* 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. |
| */ |
| |
| |
| 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; |
| } |
| } |
| |
| |
| 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); |
| } |
| } |
| |
| |
| /* |
| * 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); |
| |
| 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; |
| 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; |
| 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; |
| 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; |
| break; |
| |
| default: |
| ERREXIT(cinfo->emethods, "Not a PPM file"); |
| break; |
| } |
| |
| if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ |
| ERREXIT(cinfo->emethods, "Not a PPM file"); |
| |
| /* 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 */ |