Panda3D
pnmFileTypeJPGReader.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file pnmFileTypeJPGReader.cxx
10  * @author mike
11  * @date 2000-06-19
12  */
13 
14 #include "pnmFileTypeJPG.h"
15 
16 #ifdef HAVE_JPEG
17 
18 #include "config_pnmimagetypes.h"
19 #include "thread.h"
20 
21 // The following bit of code, for setting up jpeg_istream_src(), was lifted
22 // from jpeglib, and modified to work with istream instead of stdio.
23 
24 /*
25  * jdatasrc.c
26  *
27  * Copyright (C) 1994-1996, Thomas G. Lane.
28  * This file is part of the Independent JPEG Group's software.
29  * For conditions of distribution and use, see the accompanying README file.
30  *
31  * This file contains decompression data source routines for the case of
32  * reading JPEG data from a file (or any stdio stream). While these routines
33  * are sufficient for most applications, some will want to use a different
34  * source manager.
35  * IMPORTANT: we assume that fread() will correctly transcribe an array of
36  * JOCTETs from 8-bit-wide elements on external storage. If char is wider
37  * than 8 bits on your machine, you may need to do some tweaking.
38  */
39 
40 /* this is not a core library module, so it doesn't define JPEG_INTERNALS */
41 extern "C" {
42 #include <jpeglib.h>
43 #include <jerror.h>
44 }
45 
46 
47 /* Expanded data source object for stdio input */
48 
49 typedef struct {
50  struct jpeg_source_mgr pub; /* public fields */
51 
52  std::istream * infile; /* source stream */
53  JOCTET * buffer; /* start of buffer */
54  boolean start_of_file; /* have we gotten any data yet? */
55 } my_source_mgr;
56 
57 typedef my_source_mgr * my_src_ptr;
58 
59 #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
60 
61 
62 /*
63  * Initialize source --- called by jpeg_read_header
64  * before any data is actually read.
65  */
66 
67 METHODDEF(void)
68 init_source (j_decompress_ptr cinfo)
69 {
70  my_src_ptr src = (my_src_ptr) cinfo->src;
71 
72  /* We reset the empty-input-file flag for each image,
73  * but we don't clear the input buffer.
74  * This is correct behavior for reading a series of images from one source.
75  */
76  src->start_of_file = TRUE;
77 }
78 
79 
80 /*
81  * Fill the input buffer --- called whenever buffer is emptied.
82  *
83  * In typical applications, this should read fresh data into the buffer
84  * (ignoring the current state of next_input_byte & bytes_in_buffer),
85  * reset the pointer & count to the start of the buffer, and return TRUE
86  * indicating that the buffer has been reloaded. It is not necessary to
87  * fill the buffer entirely, only to obtain at least one more byte.
88  *
89  * There is no such thing as an EOF return. If the end of the file has been
90  * reached, the routine has a choice of ERREXIT() or inserting fake data into
91  * the buffer. In most cases, generating a warning message and inserting a
92  * fake EOI marker is the best course of action --- this will allow the
93  * decompressor to output however much of the image is there. However,
94  * the resulting error message is misleading if the real problem is an empty
95  * input file, so we handle that case specially.
96  *
97  * In applications that need to be able to suspend compression due to input
98  * not being available yet, a FALSE return indicates that no more data can be
99  * obtained right now, but more may be forthcoming later. In this situation,
100  * the decompressor will return to its caller (with an indication of the
101  * number of scanlines it has read, if any). The application should resume
102  * decompression after it has loaded more data into the input buffer. Note
103  * that there are substantial restrictions on the use of suspension --- see
104  * the documentation.
105  *
106  * When suspending, the decompressor will back up to a convenient restart point
107  * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
108  * indicate where the restart point will be if the current call returns FALSE.
109  * Data beyond this point must be rescanned after resumption, so move it to
110  * the front of the buffer rather than discarding it.
111  */
112 
113 METHODDEF(boolean)
114 fill_input_buffer (j_decompress_ptr cinfo)
115 {
116  my_src_ptr src = (my_src_ptr) cinfo->src;
117  size_t nbytes;
118 
119  src->infile->read((char *)src->buffer, INPUT_BUF_SIZE);
120  nbytes = src->infile->gcount();
122 
123  if (nbytes <= 0) {
124  if (src->start_of_file) /* Treat empty input file as fatal error */
125  ERREXIT(cinfo, JERR_INPUT_EMPTY);
126  WARNMS(cinfo, JWRN_JPEG_EOF);
127  /* Insert a fake EOI marker */
128  src->buffer[0] = (JOCTET) 0xFF;
129  src->buffer[1] = (JOCTET) JPEG_EOI;
130  nbytes = 2;
131  }
132 
133  src->pub.next_input_byte = src->buffer;
134  src->pub.bytes_in_buffer = nbytes;
135  src->start_of_file = FALSE;
136 
137  return TRUE;
138 }
139 
140 
141 /*
142  * Skip data --- used to skip over a potentially large amount of
143  * uninteresting data (such as an APPn marker).
144  *
145  * Writers of suspendable-input applications must note that skip_input_data
146  * is not granted the right to give a suspension return. If the skip extends
147  * beyond the data currently in the buffer, the buffer can be marked empty so
148  * that the next read will cause a fill_input_buffer call that can suspend.
149  * Arranging for additional bytes to be discarded before reloading the input
150  * buffer is the application writer's problem.
151  */
152 
153 METHODDEF(void)
154 skip_input_data (j_decompress_ptr cinfo, long num_bytes)
155 {
156  my_src_ptr src = (my_src_ptr) cinfo->src;
157 
158  /* Just a dumb implementation for now. Could use fseek() except
159  * it doesn't work on pipes. Not clear that being smart is worth
160  * any trouble anyway --- large skips are infrequent.
161  */
162  if (num_bytes > 0) {
163  while (num_bytes > (long) src->pub.bytes_in_buffer) {
164  num_bytes -= (long) src->pub.bytes_in_buffer;
165  (void) fill_input_buffer(cinfo);
166  /* note we assume that fill_input_buffer will never return FALSE,
167  * so suspension need not be handled.
168  */
169  }
170  src->pub.next_input_byte += (size_t) num_bytes;
171  src->pub.bytes_in_buffer -= (size_t) num_bytes;
172  }
173 }
174 
175 
176 /*
177  * An additional method that can be provided by data source modules is the
178  * resync_to_restart method for error recovery in the presence of RST markers.
179  * For the moment, this source module just uses the default resync method
180  * provided by the JPEG library. That method assumes that no backtracking
181  * is possible.
182  */
183 
184 
185 /*
186  * Terminate source --- called by jpeg_finish_decompress
187  * after all data has been read. Often a no-op.
188  *
189  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
190  * application must deal with any cleanup that should happen even
191  * for error exit.
192  */
193 
194 METHODDEF(void)
195 term_source (j_decompress_ptr cinfo)
196 {
197  /* no work necessary here */
198 }
199 
200 
201 /*
202  * Prepare for input from a stdio stream.
203  * The caller must have already opened the stream, and is responsible
204  * for closing it after finishing decompression.
205  */
206 
207 GLOBAL(void)
208 jpeg_istream_src (j_decompress_ptr cinfo, std::istream * infile)
209 {
210  my_src_ptr src;
211 
212  /* The source object and input buffer are made permanent so that a series
213  * of JPEG images can be read from the same file by calling jpeg_stdio_src
214  * only before the first one. (If we discarded the buffer at the end of
215  * one image, we'd likely lose the start of the next one.)
216  * This makes it unsafe to use this manager and a different source
217  * manager serially with the same JPEG object. Caveat programmer.
218  */
219  if (cinfo->src == nullptr) { /* first time for this JPEG object? */
220  cinfo->src = (struct jpeg_source_mgr *)
221  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
222  sizeof(my_source_mgr));
223  src = (my_src_ptr) cinfo->src;
224  src->buffer = (JOCTET *)
225  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
226  INPUT_BUF_SIZE * sizeof(JOCTET));
227  }
228 
229  src = (my_src_ptr) cinfo->src;
230  src->pub.init_source = init_source;
231  src->pub.fill_input_buffer = fill_input_buffer;
232  src->pub.skip_input_data = skip_input_data;
233  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
234  src->pub.term_source = term_source;
235  src->infile = infile;
236  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
237  src->pub.next_input_byte = nullptr; /* until buffer loaded */
238 }
239 
240 
241 
242 // The rest of the code in this file is new to Panda.
243 
244 /**
245  *
246  */
247 PNMFileTypeJPG::Reader::
248 Reader(PNMFileType *type, std::istream *file, bool owns_file, std::string magic_number) :
249  PNMReader(type, file, owns_file)
250 {
251  // Hope we can putback() more than one character.
252  for (std::string::reverse_iterator mi = magic_number.rbegin();
253  mi != magic_number.rend();
254  ++mi) {
255  _file->putback(*mi);
256  }
257  if (_file->fail()) {
258  pnmimage_jpg_cat.error()
259  << "Unable to put back magic number.\n";
260  _is_valid = false;
261  return;
262  }
263  _is_valid = true;
264 
265  /* Step 1: allocate and initialize JPEG decompression object */
266 
267  /* We set up the normal JPEG error routines, then override error_exit. */
268  _cinfo.err = jpeg_std_error(&_jerr.pub);
269 
270  /* Now we can initialize the JPEG decompression object. */
271  jpeg_create_decompress(&_cinfo);
272 
273  /* Step 2: specify data source (eg, a file) */
274  jpeg_istream_src(&_cinfo, file);
275 
276  /* Step 3: let lib jpeg know that we want to read the comment field */
277  jpeg_save_markers(&_cinfo, JPEG_COM, 0xffff);
278 
279  /* Step 4: read file parameters with jpeg_read_header() */
280  jpeg_read_header(&_cinfo, TRUE);
281  /* We can ignore the return value from jpeg_read_header since
282  * (a) suspension is not possible with the stdio data source, and
283  * (b) we passed TRUE to reject a tables-only JPEG file as an error.
284  * See libjpeg.doc for more info.
285  */
286 
287  _num_channels = _cinfo.num_components;
288  _x_size = (int)_cinfo.image_width;
289  _y_size = (int)_cinfo.image_height;
290  _maxval = MAXJSAMPLE;
291 
292  /* Step 6: set parameters for decompression */
293  _cinfo.scale_num = 1;
294  _cinfo.scale_denom = 1;
295 }
296 
297 /**
298  * This method will be called before read_data() or read_row() is called. It
299  * instructs the reader to initialize its data structures as necessary to
300  * actually perform the read operation.
301  *
302  * After this call, _x_size and _y_size should reflect the actual size that
303  * will be filled by read_data() (as possibly modified by set_read_size()).
304  */
305 void PNMFileTypeJPG::Reader::
306 prepare_read() {
307  if (_has_read_size && _read_x_size != 0 && _read_y_size != 0) {
308  // Attempt to get the scale close to our target scale.
309  int x_reduction = _cinfo.image_width / _read_x_size;
310  int y_reduction = _cinfo.image_height / _read_y_size;
311  _cinfo.scale_denom = std::max(std::min(x_reduction, y_reduction), 1);
312  }
313 
314  /* Step 7: Start decompressor */
315 
316  jpeg_start_decompress(&_cinfo);
317  /* We can ignore the return value since suspension is not possible
318  * with the stdio data source.
319  */
320 
321  _num_channels = _cinfo.output_components;
322  _x_size = (int)_cinfo.output_width;
323  _y_size = (int)_cinfo.output_height;
324 }
325 
326 /**
327  *
328  */
329 PNMFileTypeJPG::Reader::
330 ~Reader() {
331  if (_is_valid) {
332  jpeg_destroy_decompress(&_cinfo);
333  _is_valid = false;
334  }
335 }
336 
337 /**
338  * Reads in an entire image all at once, storing it in the pre-allocated
339  * _x_size * _y_size array and alpha pointers. (If the image type has no
340  * alpha channel, alpha is ignored.) Returns the number of rows correctly
341  * read.
342  *
343  * Derived classes need not override this if they instead provide
344  * supports_read_row() and read_row(), below.
345  */
346 int PNMFileTypeJPG::Reader::
347 read_data(xel *array, xelval *) {
348  if (!_is_valid) {
349  return 0;
350  }
351  JSAMPARRAY buffer; /* Output row buffer */
352  int row_stride; /* physical row width in output buffer */
353 
354  nassertr(_cinfo.output_components == 1 || _cinfo.output_components == 3, 0);
355 
356  /* We may need to do some setup of our own at this point before reading
357  * the data. After jpeg_start_decompress() we have the correct scaled
358  * output image dimensions available, as well as the output colormap
359  * if we asked for color quantization.
360  * In this example, we need to make an output work buffer of the right size.
361  */
362  /* JSAMPLEs per row in output buffer */
363  row_stride = _cinfo.output_width * _cinfo.output_components;
364  /* Make a one-row-high sample array that will go away when done with image */
365 
366  buffer = (*_cinfo.mem->alloc_sarray)
367  ((j_common_ptr) &_cinfo, JPOOL_IMAGE, row_stride, 1);
368 
369  /* Step 6: while (scan lines remain to be read) */
370  /* jpeg_read_scanlines(...); */
371 
372  /* Here we use the library's state variable cinfo.output_scanline as the
373  * loop counter, so that we don't have to keep track ourselves.
374  */
375  int x = 0;
376  while (_cinfo.output_scanline < _cinfo.output_height) {
377  /* jpeg_read_scanlines expects an array of pointers to scanlines.
378  * Here the array is only one element long, but you could ask for
379  * more than one scanline at a time if that's more convenient.
380  */
381  jpeg_read_scanlines(&_cinfo, buffer, 1);
382  /* Assume put_scanline_someplace wants a pointer and sample count. */
383  // put_scanline_someplace(buffer[0], row_stride);
384  JSAMPROW bufptr = buffer[0];
385  for (int i = 0; i < row_stride; i += _cinfo.output_components) {
386  if (_cinfo.output_components == 1) {
387  xelval val = (xelval)bufptr[i];
388  nassertr(x < _x_size * _y_size, 0);
389  PNM_ASSIGN1(array[x], val);
390  } else {
391  xelval red, grn, blu;
392  red = (xelval)bufptr[i];
393  grn = (xelval)bufptr[i+1];
394  blu = (xelval)bufptr[i+2];
395  nassertr(x < _x_size * _y_size, 0);
396  PPM_ASSIGN(array[x], red, grn, blu);
397  }
398  x++;
399  }
401  }
402 
403  /* Step 7: Finish decompression */
404 
405  jpeg_finish_decompress(&_cinfo);
406 
407  /* We can ignore the return value since suspension is not possible
408  * with the stdio data source.
409  */
410 
411  /* At this point you may want to check to see whether any corrupt-data
412  * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
413  */
414  if (_jerr.pub.num_warnings) {
415  pnmimage_jpg_cat.warning()
416  << "Jpeg data may be corrupt" << std::endl;
417  }
418 
419  return _y_size;
420 }
421 
422 #endif // HAVE_JPEG
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
Definition: thread.I:212
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is an abstract base class that defines the interface for reading image files of various types.
Definition: pnmReader.h:27
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.