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