325 lines
8.7 KiB
C
325 lines
8.7 KiB
C
/*
|
|
* 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 */
|