[AMSTREAM] Sync with Wine Staging 3.9. CORE-14656
[reactos.git] / dll / 3rdparty / libjpeg / rdppm.c
1 /*
2 * rdppm.c
3 *
4 * Copyright (C) 1991-1997, Thomas G. Lane.
5 * Modified 2009-2017 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 unsigned int maxval;
80 } ppm_source_struct;
81
82 typedef ppm_source_struct * ppm_source_ptr;
83
84
85 LOCAL(int)
86 pbm_getc (FILE * infile)
87 /* Read next char, skipping over any comments */
88 /* A comment/newline sequence is returned as a newline */
89 {
90 register int ch;
91
92 ch = getc(infile);
93 if (ch == '#') {
94 do {
95 ch = getc(infile);
96 } while (ch != '\n' && ch != EOF);
97 }
98 return ch;
99 }
100
101
102 LOCAL(unsigned int)
103 read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
104 /* Read an unsigned decimal integer from the PPM file */
105 /* Swallows one trailing character after the integer */
106 /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
107 /* This should not be a problem in practice. */
108 {
109 register int ch;
110 register unsigned int val;
111
112 /* Skip any leading whitespace */
113 do {
114 ch = pbm_getc(infile);
115 if (ch == EOF)
116 ERREXIT(cinfo, JERR_INPUT_EOF);
117 } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
118
119 if (ch < '0' || ch > '9')
120 ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
121
122 val = ch - '0';
123 while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
124 val *= 10;
125 val += ch - '0';
126 }
127 return val;
128 }
129
130
131 /*
132 * Read one row of pixels.
133 *
134 * We provide several different versions depending on input file format.
135 * In all cases, input is scaled to the size of JSAMPLE.
136 *
137 * A really fast path is provided for reading byte/sample raw files with
138 * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
139 */
140
141
142 METHODDEF(JDIMENSION)
143 get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
144 /* This version is for reading text-format PGM files with any maxval */
145 {
146 ppm_source_ptr source = (ppm_source_ptr) sinfo;
147 FILE * infile = source->pub.input_file;
148 register JSAMPROW ptr;
149 register JSAMPLE *rescale = source->rescale;
150 unsigned int maxval = source->maxval;
151 JDIMENSION col;
152
153 ptr = source->pub.buffer[0];
154 for (col = cinfo->image_width; col > 0; col--) {
155 register unsigned int temp;
156 temp = read_pbm_integer(cinfo, infile);
157 if (temp > maxval)
158 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
159 *ptr++ = rescale[temp];
160 }
161 return 1;
162 }
163
164
165 METHODDEF(JDIMENSION)
166 get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
167 /* This version is for reading text-format PPM files with any maxval */
168 {
169 ppm_source_ptr source = (ppm_source_ptr) sinfo;
170 FILE * infile = source->pub.input_file;
171 register JSAMPROW ptr;
172 register JSAMPLE *rescale = source->rescale;
173 unsigned int maxval = source->maxval;
174 JDIMENSION col;
175
176 ptr = source->pub.buffer[0];
177 for (col = cinfo->image_width; col > 0; col--) {
178 register unsigned int temp;
179 temp = read_pbm_integer(cinfo, infile);
180 if (temp > maxval)
181 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
182 *ptr++ = rescale[temp];
183 temp = read_pbm_integer(cinfo, infile);
184 if (temp > maxval)
185 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
186 *ptr++ = rescale[temp];
187 temp = read_pbm_integer(cinfo, infile);
188 if (temp > maxval)
189 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
190 *ptr++ = rescale[temp];
191 }
192 return 1;
193 }
194
195
196 METHODDEF(JDIMENSION)
197 get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
198 /* This version is for reading raw-byte-format PGM files with any maxval */
199 {
200 ppm_source_ptr source = (ppm_source_ptr) sinfo;
201 register JSAMPROW ptr;
202 register U_CHAR * bufferptr;
203 register JSAMPLE *rescale = source->rescale;
204 unsigned int maxval = source->maxval;
205 JDIMENSION col;
206
207 if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
208 ERREXIT(cinfo, JERR_INPUT_EOF);
209 ptr = source->pub.buffer[0];
210 bufferptr = source->iobuffer;
211 for (col = cinfo->image_width; col > 0; col--) {
212 register unsigned int temp;
213 temp = (unsigned int) UCH(*bufferptr++);
214 if (temp > maxval)
215 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
216 *ptr++ = rescale[temp];
217 }
218 return 1;
219 }
220
221
222 METHODDEF(JDIMENSION)
223 get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
224 /* This version is for reading raw-byte-format PPM files with any maxval */
225 {
226 ppm_source_ptr source = (ppm_source_ptr) sinfo;
227 register JSAMPROW ptr;
228 register U_CHAR * bufferptr;
229 register JSAMPLE *rescale = source->rescale;
230 unsigned int maxval = source->maxval;
231 JDIMENSION col;
232
233 if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
234 ERREXIT(cinfo, JERR_INPUT_EOF);
235 ptr = source->pub.buffer[0];
236 bufferptr = source->iobuffer;
237 for (col = cinfo->image_width; col > 0; col--) {
238 register unsigned int temp;
239 temp = (unsigned int) UCH(*bufferptr++);
240 if (temp > maxval)
241 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
242 *ptr++ = rescale[temp];
243 temp = (unsigned int) UCH(*bufferptr++);
244 if (temp > maxval)
245 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
246 *ptr++ = rescale[temp];
247 temp = (unsigned int) UCH(*bufferptr++);
248 if (temp > maxval)
249 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
250 *ptr++ = rescale[temp];
251 }
252 return 1;
253 }
254
255
256 METHODDEF(JDIMENSION)
257 get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
258 /* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
259 * In this case we just read right into the JSAMPLE buffer!
260 * Note that same code works for PPM and PGM files.
261 */
262 {
263 ppm_source_ptr source = (ppm_source_ptr) sinfo;
264
265 if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
266 ERREXIT(cinfo, JERR_INPUT_EOF);
267 return 1;
268 }
269
270
271 METHODDEF(JDIMENSION)
272 get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
273 /* This version is for reading raw-word-format PGM files with any maxval */
274 {
275 ppm_source_ptr source = (ppm_source_ptr) sinfo;
276 register JSAMPROW ptr;
277 register U_CHAR * bufferptr;
278 register JSAMPLE *rescale = source->rescale;
279 unsigned int maxval = source->maxval;
280 JDIMENSION col;
281
282 if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
283 ERREXIT(cinfo, JERR_INPUT_EOF);
284 ptr = source->pub.buffer[0];
285 bufferptr = source->iobuffer;
286 for (col = cinfo->image_width; col > 0; col--) {
287 register unsigned int temp;
288 temp = ((unsigned int) UCH(*bufferptr++)) << 8;
289 temp |= (unsigned int) UCH(*bufferptr++);
290 if (temp > maxval)
291 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
292 *ptr++ = rescale[temp];
293 }
294 return 1;
295 }
296
297
298 METHODDEF(JDIMENSION)
299 get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
300 /* This version is for reading raw-word-format PPM files with any maxval */
301 {
302 ppm_source_ptr source = (ppm_source_ptr) sinfo;
303 register JSAMPROW ptr;
304 register U_CHAR * bufferptr;
305 register JSAMPLE *rescale = source->rescale;
306 unsigned int maxval = source->maxval;
307 JDIMENSION col;
308
309 if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
310 ERREXIT(cinfo, JERR_INPUT_EOF);
311 ptr = source->pub.buffer[0];
312 bufferptr = source->iobuffer;
313 for (col = cinfo->image_width; col > 0; col--) {
314 register unsigned int temp;
315 temp = ((unsigned int) UCH(*bufferptr++)) << 8;
316 temp |= (unsigned int) UCH(*bufferptr++);
317 if (temp > maxval)
318 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
319 *ptr++ = rescale[temp];
320 temp = ((unsigned int) UCH(*bufferptr++)) << 8;
321 temp |= (unsigned int) UCH(*bufferptr++);
322 if (temp > maxval)
323 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
324 *ptr++ = rescale[temp];
325 temp = ((unsigned int) UCH(*bufferptr++)) << 8;
326 temp |= (unsigned int) UCH(*bufferptr++);
327 if (temp > maxval)
328 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
329 *ptr++ = rescale[temp];
330 }
331 return 1;
332 }
333
334
335 /*
336 * Read the file header; return image size and component count.
337 */
338
339 METHODDEF(void)
340 start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
341 {
342 ppm_source_ptr source = (ppm_source_ptr) sinfo;
343 int c;
344 unsigned int w, h, maxval;
345 boolean need_iobuffer, use_raw_buffer, need_rescale;
346
347 if (getc(source->pub.input_file) != 'P')
348 ERREXIT(cinfo, JERR_PPM_NOT);
349
350 c = getc(source->pub.input_file); /* subformat discriminator character */
351
352 /* detect unsupported variants (ie, PBM) before trying to read header */
353 switch (c) {
354 case '2': /* it's a text-format PGM file */
355 case '3': /* it's a text-format PPM file */
356 case '5': /* it's a raw-format PGM file */
357 case '6': /* it's a raw-format PPM file */
358 break;
359 default:
360 ERREXIT(cinfo, JERR_PPM_NOT);
361 break;
362 }
363
364 /* fetch the remaining header info */
365 w = read_pbm_integer(cinfo, source->pub.input_file);
366 h = read_pbm_integer(cinfo, source->pub.input_file);
367 maxval = read_pbm_integer(cinfo, source->pub.input_file);
368
369 if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
370 ERREXIT(cinfo, JERR_PPM_NOT);
371
372 if (((long) w >> 24) || /* sanity check for buffer allocation below */
373 ((long) maxval >> 16)) /* support max 16-bit (2-byte) sample values */
374 ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
375
376 cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
377 cinfo->image_width = (JDIMENSION) w;
378 cinfo->image_height = (JDIMENSION) h;
379 source->maxval = maxval;
380
381 /* initialize flags to most common settings */
382 need_iobuffer = TRUE; /* do we need an I/O buffer? */
383 use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */
384 need_rescale = TRUE; /* do we need a rescale array? */
385
386 switch (c) {
387 case '2': /* it's a text-format PGM file */
388 cinfo->input_components = 1;
389 cinfo->in_color_space = JCS_GRAYSCALE;
390 TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
391 source->pub.get_pixel_rows = get_text_gray_row;
392 need_iobuffer = FALSE;
393 break;
394
395 case '3': /* it's a text-format PPM file */
396 cinfo->input_components = 3;
397 cinfo->in_color_space = JCS_RGB;
398 TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
399 source->pub.get_pixel_rows = get_text_rgb_row;
400 need_iobuffer = FALSE;
401 break;
402
403 case '5': /* it's a raw-format PGM file */
404 cinfo->input_components = 1;
405 cinfo->in_color_space = JCS_GRAYSCALE;
406 TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
407 if (maxval > 255) {
408 source->pub.get_pixel_rows = get_word_gray_row;
409 } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
410 source->pub.get_pixel_rows = get_raw_row;
411 use_raw_buffer = TRUE;
412 need_rescale = FALSE;
413 } else {
414 source->pub.get_pixel_rows = get_scaled_gray_row;
415 }
416 break;
417
418 case '6': /* it's a raw-format PPM file */
419 cinfo->input_components = 3;
420 cinfo->in_color_space = JCS_RGB;
421 TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
422 if (maxval > 255) {
423 source->pub.get_pixel_rows = get_word_rgb_row;
424 } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
425 source->pub.get_pixel_rows = get_raw_row;
426 use_raw_buffer = TRUE;
427 need_rescale = FALSE;
428 } else {
429 source->pub.get_pixel_rows = get_scaled_rgb_row;
430 }
431 break;
432 }
433
434 /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
435 if (need_iobuffer) {
436 source->buffer_width = (size_t) w * cinfo->input_components *
437 ((maxval <= 255) ? SIZEOF(U_CHAR) : (2 * SIZEOF(U_CHAR)));
438 source->iobuffer = (U_CHAR *) (*cinfo->mem->alloc_small)
439 ((j_common_ptr) cinfo, JPOOL_IMAGE, source->buffer_width);
440 }
441
442 /* Create compressor input buffer. */
443 if (use_raw_buffer) {
444 /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
445 /* Synthesize a JSAMPARRAY pointer structure */
446 /* Cast here implies near->far pointer conversion on PCs */
447 source->pixrow = (JSAMPROW) source->iobuffer;
448 source->pub.buffer = & source->pixrow;
449 source->pub.buffer_height = 1;
450 } else {
451 /* Need to translate anyway, so make a separate sample buffer. */
452 source->pub.buffer = (*cinfo->mem->alloc_sarray)
453 ((j_common_ptr) cinfo, JPOOL_IMAGE,
454 (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
455 source->pub.buffer_height = 1;
456 }
457
458 /* Compute the rescaling array if required. */
459 if (need_rescale) {
460 INT32 val, half_maxval;
461
462 /* On 16-bit-int machines we have to be careful of maxval = 65535 */
463 source->rescale = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
464 JPOOL_IMAGE, (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
465 half_maxval = maxval / 2;
466 for (val = 0; val <= (INT32) maxval; val++) {
467 /* The multiplication here must be done in 32 bits to avoid overflow */
468 source->rescale[val] = (JSAMPLE) ((val * MAXJSAMPLE + half_maxval) / maxval);
469 }
470 }
471 }
472
473
474 /*
475 * Finish up at the end of the file.
476 */
477
478 METHODDEF(void)
479 finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
480 {
481 /* no work */
482 }
483
484
485 /*
486 * The module selection routine for PPM format input.
487 */
488
489 GLOBAL(cjpeg_source_ptr)
490 jinit_read_ppm (j_compress_ptr cinfo)
491 {
492 ppm_source_ptr source;
493
494 /* Create module interface object */
495 source = (ppm_source_ptr)
496 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
497 SIZEOF(ppm_source_struct));
498 /* Fill in method ptrs, except get_pixel_rows which start_input sets */
499 source->pub.start_input = start_input_ppm;
500 source->pub.finish_input = finish_input_ppm;
501
502 return &source->pub;
503 }
504
505 #endif /* PPM_SUPPORTED */