Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6417 ashmew2 1
/*
2
 * rdppm.c
3
 *
4
 * Copyright (C) 1991-1997, 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 extended 2-byte-per-sample raw PPM/PGM formats are supported.
10
 * The PBMPLUS library is NOT required to compile this software
11
 * (but it is highly useful as a set of PPM image manipulation programs).
12
 *
13
 * These routines may need modification for non-Unix environments or
14
 * specialized applications.  As they stand, they assume input from
15
 * an ordinary stdio stream.  They further assume that reading begins
16
 * at the start of the file; start_input may need work if the
17
 * user interface has already read some data (e.g., to determine that
18
 * the file is indeed PPM format).
19
 */
20
 
21
#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
22
 
23
#ifdef PPM_SUPPORTED
24
 
25
 
26
/* Portions of this code are based on the PBMPLUS library, which is:
27
**
28
** Copyright (C) 1988 by Jef Poskanzer.
29
**
30
** Permission to use, copy, modify, and distribute this software and its
31
** documentation for any purpose and without fee is hereby granted, provided
32
** that the above copyright notice appear in all copies and that both that
33
** copyright notice and this permission notice appear in supporting
34
** documentation.  This software is provided "as is" without express or
35
** implied warranty.
36
*/
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
#ifdef CHAR_IS_UNSIGNED
46
typedef char U_CHAR;
47
#define UCH(x)	((int) (x))
48
#else
49
typedef char U_CHAR;
50
#define UCH(x)	((int) (x) & 0xFF)
51
#endif
52
#endif /* HAVE_UNSIGNED_CHAR */
53
 
54
 
55
#define	ReadOK(file,buffer,len)	(JFREAD(file,buffer,len) == ((size_t) (len)))
56
 
57
 
58
/*
59
 * On most systems, reading individual bytes with getc() is drastically less
60
 * efficient than buffering a row at a time with fread().  On PCs, we must
61
 * allocate the buffer in near data space, because we are assuming small-data
62
 * memory model, wherein fread() can't reach far memory.  If you need to
63
 * process very wide images on a PC, you might have to compile in large-memory
64
 * model, or else replace fread() with a getc() loop --- which will be much
65
 * slower.
66
 */
67
 
68
 
69
/* Private version of data source object */
70
 
71
typedef struct {
72
  struct cjpeg_source_struct pub; /* public fields */
73
 
74
  U_CHAR *iobuffer;		/* non-FAR pointer to I/O buffer */
75
  JSAMPROW pixrow;		/* FAR pointer to same */
76
  size_t buffer_width;		/* width of I/O buffer */
77
  JSAMPLE *rescale;		/* => maxval-remapping array, or NULL */
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
 
140
METHODDEF(JDIMENSION)
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
  JDIMENSION col;
149
 
150
  ptr = source->pub.buffer[0];
151
  for (col = cinfo->image_width; col > 0; col--) {
152
    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
153
  }
154
  return 1;
155
}
156
 
157
 
158
METHODDEF(JDIMENSION)
159
get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
160
/* This version is for reading text-format PPM files with any maxval */
161
{
162
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
163
  FILE * infile = source->pub.input_file;
164
  register JSAMPROW ptr;
165
  register JSAMPLE *rescale = source->rescale;
166
  JDIMENSION col;
167
 
168
  ptr = source->pub.buffer[0];
169
  for (col = cinfo->image_width; col > 0; col--) {
170
    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
171
    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
172
    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
173
  }
174
  return 1;
175
}
176
 
177
 
178
METHODDEF(JDIMENSION)
179
get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
180
/* This version is for reading raw-byte-format PGM files with any maxval */
181
{
182
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
183
  register JSAMPROW ptr;
184
  register U_CHAR * bufferptr;
185
  register JSAMPLE *rescale = source->rescale;
186
  JDIMENSION col;
187
 
188
  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
189
    ERREXIT(cinfo, JERR_INPUT_EOF);
190
  ptr = source->pub.buffer[0];
191
  bufferptr = source->iobuffer;
192
  for (col = cinfo->image_width; col > 0; col--) {
193
    *ptr++ = rescale[UCH(*bufferptr++)];
194
  }
195
  return 1;
196
}
197
 
198
 
199
METHODDEF(JDIMENSION)
200
get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
201
/* This version is for reading raw-byte-format PPM files with any maxval */
202
{
203
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
204
  register JSAMPROW ptr;
205
  register U_CHAR * bufferptr;
206
  register JSAMPLE *rescale = source->rescale;
207
  JDIMENSION col;
208
 
209
  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
210
    ERREXIT(cinfo, JERR_INPUT_EOF);
211
  ptr = source->pub.buffer[0];
212
  bufferptr = source->iobuffer;
213
  for (col = cinfo->image_width; col > 0; col--) {
214
    *ptr++ = rescale[UCH(*bufferptr++)];
215
    *ptr++ = rescale[UCH(*bufferptr++)];
216
    *ptr++ = rescale[UCH(*bufferptr++)];
217
  }
218
  return 1;
219
}
220
 
221
 
222
METHODDEF(JDIMENSION)
223
get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
224
/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
225
 * In this case we just read right into the JSAMPLE buffer!
226
 * Note that same code works for PPM and PGM files.
227
 */
228
{
229
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
230
 
231
  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
232
    ERREXIT(cinfo, JERR_INPUT_EOF);
233
  return 1;
234
}
235
 
236
 
237
METHODDEF(JDIMENSION)
238
get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
239
/* This version is for reading raw-word-format PGM files with any maxval */
240
{
241
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
242
  register JSAMPROW ptr;
243
  register U_CHAR * bufferptr;
244
  register JSAMPLE *rescale = source->rescale;
245
  JDIMENSION col;
246
 
247
  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
248
    ERREXIT(cinfo, JERR_INPUT_EOF);
249
  ptr = source->pub.buffer[0];
250
  bufferptr = source->iobuffer;
251
  for (col = cinfo->image_width; col > 0; col--) {
252
    register int temp;
253
    temp  = UCH(*bufferptr++);
254
    temp |= UCH(*bufferptr++) << 8;
255
    *ptr++ = rescale[temp];
256
  }
257
  return 1;
258
}
259
 
260
 
261
METHODDEF(JDIMENSION)
262
get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
263
/* This version is for reading raw-word-format PPM files with any maxval */
264
{
265
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
266
  register JSAMPROW ptr;
267
  register U_CHAR * bufferptr;
268
  register JSAMPLE *rescale = source->rescale;
269
  JDIMENSION col;
270
 
271
  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
272
    ERREXIT(cinfo, JERR_INPUT_EOF);
273
  ptr = source->pub.buffer[0];
274
  bufferptr = source->iobuffer;
275
  for (col = cinfo->image_width; col > 0; col--) {
276
    register int temp;
277
    temp  = UCH(*bufferptr++);
278
    temp |= UCH(*bufferptr++) << 8;
279
    *ptr++ = rescale[temp];
280
    temp  = UCH(*bufferptr++);
281
    temp |= UCH(*bufferptr++) << 8;
282
    *ptr++ = rescale[temp];
283
    temp  = UCH(*bufferptr++);
284
    temp |= UCH(*bufferptr++) << 8;
285
    *ptr++ = rescale[temp];
286
  }
287
  return 1;
288
}
289
 
290
 
291
/*
292
 * Read the file header; return image size and component count.
293
 */
294
 
295
METHODDEF(void)
296
start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
297
{
298
  ppm_source_ptr source = (ppm_source_ptr) sinfo;
299
  int c;
300
  unsigned int w, h, maxval;
301
  boolean need_iobuffer, use_raw_buffer, need_rescale;
302
 
303
  if (getc(source->pub.input_file) != 'P')
304
    ERREXIT(cinfo, JERR_PPM_NOT);
305
 
306
  c = getc(source->pub.input_file); /* subformat discriminator character */
307
 
308
  /* detect unsupported variants (ie, PBM) before trying to read header */
309
  switch (c) {
310
  case '2':			/* it's a text-format PGM file */
311
  case '3':			/* it's a text-format PPM file */
312
  case '5':			/* it's a raw-format PGM file */
313
  case '6':			/* it's a raw-format PPM file */
314
    break;
315
  default:
316
    ERREXIT(cinfo, JERR_PPM_NOT);
317
    break;
318
  }
319
 
320
  /* fetch the remaining header info */
321
  w = read_pbm_integer(cinfo, source->pub.input_file);
322
  h = read_pbm_integer(cinfo, source->pub.input_file);
323
  maxval = read_pbm_integer(cinfo, source->pub.input_file);
324
 
325
  if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
326
    ERREXIT(cinfo, JERR_PPM_NOT);
327
 
328
  cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
329
  cinfo->image_width = (JDIMENSION) w;
330
  cinfo->image_height = (JDIMENSION) h;
331
 
332
  /* initialize flags to most common settings */
333
  need_iobuffer = TRUE;		/* do we need an I/O buffer? */
334
  use_raw_buffer = FALSE;	/* do we map input buffer onto I/O buffer? */
335
  need_rescale = TRUE;		/* do we need a rescale array? */
336
 
337
  switch (c) {
338
  case '2':			/* it's a text-format PGM file */
339
    cinfo->input_components = 1;
340
    cinfo->in_color_space = JCS_GRAYSCALE;
341
    TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
342
    source->pub.get_pixel_rows = get_text_gray_row;
343
    need_iobuffer = FALSE;
344
    break;
345
 
346
  case '3':			/* it's a text-format PPM file */
347
    cinfo->input_components = 3;
348
    cinfo->in_color_space = JCS_RGB;
349
    TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
350
    source->pub.get_pixel_rows = get_text_rgb_row;
351
    need_iobuffer = FALSE;
352
    break;
353
 
354
  case '5':			/* it's a raw-format PGM file */
355
    cinfo->input_components = 1;
356
    cinfo->in_color_space = JCS_GRAYSCALE;
357
    TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
358
    if (maxval > 255) {
359
      source->pub.get_pixel_rows = get_word_gray_row;
360
    } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
361
      source->pub.get_pixel_rows = get_raw_row;
362
      use_raw_buffer = TRUE;
363
      need_rescale = FALSE;
364
    } else {
365
      source->pub.get_pixel_rows = get_scaled_gray_row;
366
    }
367
    break;
368
 
369
  case '6':			/* it's a raw-format PPM file */
370
    cinfo->input_components = 3;
371
    cinfo->in_color_space = JCS_RGB;
372
    TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
373
    if (maxval > 255) {
374
      source->pub.get_pixel_rows = get_word_rgb_row;
375
    } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
376
      source->pub.get_pixel_rows = get_raw_row;
377
      use_raw_buffer = TRUE;
378
      need_rescale = FALSE;
379
    } else {
380
      source->pub.get_pixel_rows = get_scaled_rgb_row;
381
    }
382
    break;
383
  }
384
 
385
  /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
386
  if (need_iobuffer) {
387
    source->buffer_width = (size_t) w * cinfo->input_components *
388
      ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR)));
389
    source->iobuffer = (U_CHAR *)
390
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
391
				  source->buffer_width);
392
  }
393
 
394
  /* Create compressor input buffer. */
395
  if (use_raw_buffer) {
396
    /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
397
    /* Synthesize a JSAMPARRAY pointer structure */
398
    /* Cast here implies near->far pointer conversion on PCs */
399
    source->pixrow = (JSAMPROW) source->iobuffer;
400
    source->pub.buffer = & source->pixrow;
401
    source->pub.buffer_height = 1;
402
  } else {
403
    /* Need to translate anyway, so make a separate sample buffer. */
404
    source->pub.buffer = (*cinfo->mem->alloc_sarray)
405
      ((j_common_ptr) cinfo, JPOOL_IMAGE,
406
       (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
407
    source->pub.buffer_height = 1;
408
  }
409
 
410
  /* Compute the rescaling array if required. */
411
  if (need_rescale) {
412
    INT32 val, half_maxval;
413
 
414
    /* On 16-bit-int machines we have to be careful of maxval = 65535 */
415
    source->rescale = (JSAMPLE *)
416
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
417
				  (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
418
    half_maxval = maxval / 2;
419
    for (val = 0; val <= (INT32) maxval; val++) {
420
      /* The multiplication here must be done in 32 bits to avoid overflow */
421
      source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
422
    }
423
  }
424
}
425
 
426
 
427
/*
428
 * Finish up at the end of the file.
429
 */
430
 
431
METHODDEF(void)
432
finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
433
{
434
  /* no work */
435
}
436
 
437
 
438
/*
439
 * The module selection routine for PPM format input.
440
 */
441
 
442
GLOBAL(cjpeg_source_ptr)
443
jinit_read_ppm (j_compress_ptr cinfo)
444
{
445
  ppm_source_ptr source;
446
 
447
  /* Create module interface object */
448
  source = (ppm_source_ptr)
449
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
450
				  SIZEOF(ppm_source_struct));
451
  /* Fill in method ptrs, except get_pixel_rows which start_input sets */
452
  source->pub.start_input = start_input_ppm;
453
  source->pub.finish_input = finish_input_ppm;
454
 
455
  return (cjpeg_source_ptr) source;
456
}
457
 
458
#endif /* PPM_SUPPORTED */