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