vil_jpeg_source_mgr.cxx
Go to the documentation of this file.
1 // This is core/vil/file_formats/vil_jpeg_source_mgr.cxx
2 //:
3 // \file
4 // \author fsm
5 // \verbatim
6 // Modifications
7 // 11 Oct 2002 Ian Scott - converted to vil
8 //\endverbatim
9 
10 #include <cstddef>
11 #include <limits>
12 #include "vil_jpeg_source_mgr.h"
13 #include <cassert>
14 #ifdef _MSC_VER
15 # include <vcl_msvc_warnings.h>
16 #endif
17 #include <vil/vil_stream.h>
18 
19 #define STATIC /*static*/
20 
21 // In ANSI C, and indeed any rational implementation, std::size_t is also the
22 // type returned by sizeof(). However, it seems there are some irrational
23 // implementations out there, in which sizeof() returns an int even though
24 // std::size_t is defined as long or unsigned long. To ensure consistent results
25 // we always use this SIZEOF() macro in place of using sizeof() directly.
26 //
27 #define SIZEOF(object) ((std::size_t) sizeof(object))
28 
29 // Implement a jpeg_source_manager for vil_stream *.
30 // Adapted by fsm from the FILE * version in jdatasrc.c
31 
32 #define vil_jpeg_INPUT_BUF_SIZE 4096 // choose an efficiently fread'able size
34 
35 
36 // * Initialize source --- called by jpeg_read_header
37 // * before any data is actually read.
38 STATIC
39 void
40 vil_jpeg_init_source (j_decompress_ptr cinfo)
41 {
42  auto src = ( vil_jpeg_srcptr )( cinfo->src );
43 
44 #ifdef DEBUG
45  std::cerr << "vil_jpeg_init_source() " << src << '\n';
46 #endif
47 
48  // We reset the empty-input-file flag for each image,
49  // but we don't clear the input buffer.
50  // This is correct behavior for reading a series of images from one source.
51  src->start_of_file = TRUE;
52 }
53 
54 //: Fill the input buffer --- called whenever buffer is emptied.
55 //
56 // In typical applications, this should read fresh data into the buffer
57 // (ignoring the current state of next_input_byte & bytes_in_buffer),
58 // reset the pointer & count to the start of the buffer, and return TRUE
59 // indicating that the buffer has been reloaded. It is not necessary to
60 // fill the buffer entirely, only to obtain at least one more byte.
61 //
62 // There is no such thing as an EOF return. If the end of the file has been
63 // reached, the routine has a choice of ERREXIT() or inserting fake data into
64 // the buffer. In most cases, generating a warning message and inserting a
65 // fake EOI marker is the best course of action --- this will allow the
66 // decompressor to output however much of the image is there. However,
67 // the resulting error message is misleading if the real problem is an empty
68 // input file, so we handle that case specially.
69 //
70 // In applications that need to be able to suspend compression due to input
71 // not being available yet, a FALSE return indicates that no more data can be
72 // obtained right now, but more may be forthcoming later. In this situation,
73 // the decompressor will return to its caller (with an indication of the
74 // number of scanlines it has read, if any). The application should resume
75 // decompression after it has loaded more data into the input buffer. Note
76 // that there are substantial restrictions on the use of suspension --- see
77 // the documentation.
78 //
79 // When suspending, the decompressor will back up to a convenient restart point
80 // (typically the start of the current MCU). next_input_byte & bytes_in_buffer
81 // indicate where the restart point will be if the current call returns FALSE.
82 // Data beyond this point must be rescanned after resumption, so move it to
83 // the front of the buffer rather than discarding it.
84 STATIC
85 jpeg_boolean
86 vil_jpeg_fill_input_buffer (j_decompress_ptr cinfo)
87 {
88  auto src = ( vil_jpeg_srcptr )( cinfo->src );
89 
90  vil_streampos nbytes = src->stream->read(src->buffer, vil_jpeg_INPUT_BUF_SIZE);
91 
92  if (nbytes <= 0) {
93  if (src->start_of_file) // Treat empty input file as fatal error
94  ERREXIT(cinfo, JERR_INPUT_EMPTY);
95  WARNMS(cinfo, JWRN_JPEG_EOF);
96  // Insert a fake EOI marker
97  src->buffer[0] = (JOCTET) 0xFF;
98  src->buffer[1] = (JOCTET) JPEG_EOI;
99  nbytes = 2;
100  }
101 
102  src->base.next_input_byte = src->buffer;
103  //original JPEG (non-j2k) files aren't usually very big
104  //so this assert should be no problem
105  assert( (std::size_t)nbytes <= std::numeric_limits< std::size_t >::max() );
106  src->base.bytes_in_buffer = (std::size_t)nbytes;
107  src->start_of_file = FALSE;
108 
109  return TRUE;
110 }
111 
112 //: Skip data --- used to skip over a potentially large amount of uninteresting data (such as an APPn marker).
113 //
114 // Writers of suspendable-input applications must note that skip_input_data
115 // is not granted the right to give a suspension return. If the skip extends
116 // beyond the data currently in the buffer, the buffer can be marked empty so
117 // that the next read will cause a fill_input_buffer call that can suspend.
118 // Arranging for additional bytes to be discarded before reloading the input
119 // buffer is the application writer's problem.
120 STATIC
121 void
122 vil_jpeg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
123 {
124  auto src = ( vil_jpeg_srcptr )( cinfo->src );
125 
126  // Just a dumb implementation for now. Could use fseek() except
127  // it doesn't work on pipes. Not clear that being smart is worth
128  // any trouble anyway --- large skips are infrequent.
129  //
130  if (num_bytes > 0) {
131  while (num_bytes > (long) src->base.bytes_in_buffer) {
132  num_bytes -= (long) src->base.bytes_in_buffer;
134  // note we assume that fill_input_buffer will never return FALSE,
135  // so suspension need not be handled.
136  }
137  src->base.next_input_byte += (std::size_t) num_bytes;
138  src->base.bytes_in_buffer -= (std::size_t) num_bytes;
139  }
140 }
141 
142 
143 //: Terminate source --- called by jpeg_finish_decompress after all data has been read. Often a no-op.
144 //
145 // \note \e not called by jpeg_abort or jpeg_destroy; surrounding
146 // application must deal with any cleanup that should happen even
147 // for error exit.
148 STATIC
149 void
150 vil_jpeg_term_source (j_decompress_ptr /*cinfo*/)
151 {
152  // no work necessary here
153 }
154 
155 STATIC
156 void
157 vil_jpeg_stream_src_set (j_decompress_ptr cinfo, vil_stream *vs)
158 {
159  // The source object and input buffer are made permanent so that a series
160  // of JPEG images can be read from the same file by calling vil_jpeg_stream_src
161  // only before the first one. (If we discarded the buffer at the end of
162  // one image, we'd likely lose the start of the next one.)
163  // This makes it unsafe to use this manager and a different source
164  // manager serially with the same JPEG object. Caveat programmer.
165  assert(! ( vil_jpeg_srcptr )( cinfo->src )); // check unused
166 
167 #ifdef DEBUG
168  std::cerr << "vil_jpeg_stream_src_set() : creating new data source\n";
169 #endif
170 
171  auto src = (vil_jpeg_srcptr) // allocate
172  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
173  JPOOL_PERMANENT,
175  // set pointer in cinfo
176  cinfo->src = reinterpret_cast<struct jpeg_source_mgr *>(src);
177 
178  // set fields in src :
179  src->stream = vs;
180 
181  src->buffer = (JOCTET *)
182  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
183  JPOOL_PERMANENT,
184  vil_jpeg_INPUT_BUF_SIZE * SIZEOF(JOCTET));
185 
186  src->start_of_file = TRUE;
187 
188  // fill in methods in base class :
189  src->base.init_source = vil_jpeg_init_source;
190  src->base.fill_input_buffer = vil_jpeg_fill_input_buffer;
191  src->base.skip_input_data = vil_jpeg_skip_input_data;
192  src->base.resync_to_restart = jpeg_resync_to_restart; // use default method
193  src->base.term_source = vil_jpeg_term_source;
194 }
195 
196 STATIC
197 void
198 vil_jpeg_stream_src_rewind(j_decompress_ptr cinfo, vil_stream *vs)
199 {
200  // verify
201  assert((vil_jpeg_srcptr)(cinfo->src) != nullptr);
202  assert(((vil_jpeg_srcptr)(cinfo->src))->stream == vs);
203 
204  cinfo->src->bytes_in_buffer = 0; // forces fill_input_buffer on first read
205  cinfo->src->next_input_byte = nullptr; // until buffer loaded
206 
207  vs->seek(0L);
208 }
Stream interface for VIL image loaders.
vil_jpeg_stream_source_mgr * vil_jpeg_srcptr
STATIC void vil_jpeg_stream_src_set(j_decompress_ptr cinfo, vil_stream *vs)
virtual void seek(vil_streampos position)=0
Goto file pointer.
this is the data source structure which allows JPEG to read from a vil_stream.
#define STATIC
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
STATIC jpeg_boolean vil_jpeg_fill_input_buffer(j_decompress_ptr cinfo)
Fill the input buffer — called whenever buffer is emptied.
#define SIZEOF(object)
STATIC void vil_jpeg_stream_src_rewind(j_decompress_ptr cinfo, vil_stream *vs)
STATIC void vil_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
Skip data — used to skip over a potentially large amount of uninteresting data (such as an APPn marke...
vxl_int_32 vil_streampos
Definition: vil_stream.h:16
#define vil_jpeg_INPUT_BUF_SIZE
STATIC void vil_jpeg_init_source(j_decompress_ptr cinfo)
STATIC void vil_jpeg_term_source(j_decompress_ptr)
Terminate source — called by jpeg_finish_decompress after all data has been read. Often a no-op.