libopenraw
jfifcontainer.cpp
1 /*
2  * libopenraw - jfifcontainer.cpp
3  *
4  * Copyright (C) 2006-2016 Hubert Figuiere
5  *
6  * This library is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation, either version 3 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #include <setjmp.h>
23 #include <fcntl.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <memory>
27 
28 namespace JPEG {
29 /*
30  * The extern "C" below is REQUIRED for libjpeg-mmx-dev
31  * as found on debian because some people have this installed.
32  */
33 extern "C" {
34 #include <jpeglib.h>
35 }
36 }
37 
38 #include <libopenraw/debug.h>
39 
40 #include "bitmapdata.hpp"
41 #include "io/stream.hpp"
42 #include "io/streamclone.hpp"
43 #include "trace.hpp"
44 #include "jfifcontainer.hpp"
45 #include "ifdfilecontainer.hpp"
46 
47 namespace OpenRaw {
48 
49 using namespace Debug;
50 
51 namespace Internals {
52 
55 #define BUF_SIZE 1024
56 
57 typedef struct {
58  struct JPEG::jpeg_source_mgr pub;
59  JfifContainer * self;
60  off_t offset;
61  JPEG::JOCTET* buf;
62 } jpeg_src_t;
63 
64 JfifContainer::JfifContainer(const IO::Stream::Ptr &_file, off_t _offset)
65  : RawContainer(_file, _offset),
66  m_cinfo(), m_jerr(),
67  m_headerLoaded(false),
68  m_ifd(nullptr)
69 {
70  setEndian(ENDIAN_BIG);
71  /* this is a hack because jpeg_create_decompress is
72  * implemented as a Macro
73  */
74  using namespace JPEG;
75 
76  m_cinfo.err = JPEG::jpeg_std_error(&m_jerr);
77  m_jerr.error_exit = &j_error_exit;
78  JPEG::jpeg_create_decompress(&m_cinfo);
79 
80  /* inspired by jdatasrc.c */
81 
82  jpeg_src_t *src = (jpeg_src_t *)
83  (*m_cinfo.mem->alloc_small)((JPEG::j_common_ptr)&m_cinfo,
84  JPOOL_PERMANENT,
85  sizeof(jpeg_src_t));
86  m_cinfo.src = (JPEG::jpeg_source_mgr*)src;
87  src->pub.init_source = j_init_source;
88  src->pub.fill_input_buffer = j_fill_input_buffer;
89  src->pub.skip_input_data = j_skip_input_data;
90  src->pub.resync_to_restart = JPEG::jpeg_resync_to_restart;
91  src->pub.term_source = j_term_source;
92  src->self = this;
93  src->pub.bytes_in_buffer = 0;
94  src->pub.next_input_byte = nullptr;
95  src->buf = (JPEG::JOCTET*)(*m_cinfo.mem->alloc_small)
96  ((JPEG::j_common_ptr)&m_cinfo,
97  JPOOL_PERMANENT,
98  BUF_SIZE * sizeof(JPEG::JOCTET));
99 }
100 
102 {
103  JPEG::jpeg_destroy_decompress(&m_cinfo);
104  delete m_ifd;
105 }
106 
107 
108 bool JfifContainer::getDimensions(uint32_t &x, uint32_t &y)
109 {
110  if(!m_headerLoaded) {
111  if (_loadHeader() == 0) {
112  Trace(DEBUG1) << "load header failed\n";
113  return false;
114  }
115  }
116  x = m_cinfo.output_width;
117  y = m_cinfo.output_height;
118  return true;
119 }
120 
121 
122 bool JfifContainer::getDecompressedData(BitmapData &data)
123 {
124  if(!m_headerLoaded) {
125  if (_loadHeader() == 0) {
126  Trace(DEBUG1) << "load header failed\n";
127  return false;
128  }
129  }
130  if (::setjmp(m_jpegjmp) != 0) {
131  return false;
132  }
133  JPEG::jpeg_start_decompress(&m_cinfo);
134  int row_size = m_cinfo.output_width * m_cinfo.output_components;
135  char *dataPtr
136  = (char*)data.allocData(row_size * m_cinfo.output_height);
137  char *currentPtr = dataPtr;
138  JPEG::JSAMPARRAY buffer
139  = (*m_cinfo.mem->alloc_sarray)((JPEG::j_common_ptr)&m_cinfo,
140  JPOOL_IMAGE, row_size,
141  1);
142  while (m_cinfo.output_scanline < m_cinfo.output_height) {
143  jpeg_read_scanlines(&m_cinfo, buffer, 1);
144  memcpy(currentPtr, buffer, row_size);
145  currentPtr += row_size;
146  }
147  data.setDimensions(m_cinfo.output_width, m_cinfo.output_height);
148 
149  JPEG::jpeg_finish_decompress(&m_cinfo);
150  return true;
151 }
152 
153 
154 int JfifContainer::_loadHeader()
155 {
156 
157  m_file->seek(0, SEEK_SET);
158 
159  if (::setjmp(m_jpegjmp) == 0) {
160  int ret = JPEG::jpeg_read_header(&m_cinfo, TRUE);
161  //Trace(DEBUG1) << "jpeg_read_header " << ret << "\n";
162 
163  JPEG::jpeg_calc_output_dimensions(&m_cinfo);
164  m_headerLoaded = (ret == 1);
165  return ret;
166  }
167  return 0;
168 }
169 
170 
171 void JfifContainer::j_error_exit(JPEG::j_common_ptr cinfo)
172 {
173  (*cinfo->err->output_message) (cinfo);
174  JfifContainer *self = ((jpeg_src_t *)(((JPEG::j_decompress_ptr)cinfo)->src))->self;
175  ::longjmp(self->m_jpegjmp, 1);
176 }
177 
178 void JfifContainer::j_init_source(JPEG::j_decompress_ptr)
179 {
180 }
181 
182 
183 JPEG::boolean
184 JfifContainer::j_fill_input_buffer(JPEG::j_decompress_ptr cinfo)
185 {
186  jpeg_src_t *src = (jpeg_src_t*)cinfo->src;
187  JfifContainer *self = src->self;
188  int n = self->file()->read(src->buf, BUF_SIZE * sizeof(*src->buf));
189  if (n >= 0) {
190  src->pub.next_input_byte = src->buf;
191  src->pub.bytes_in_buffer = n;
192  }
193  else {
194  src->pub.next_input_byte = nullptr;
195  src->pub.bytes_in_buffer = 0;
196  }
197  return TRUE;
198 }
199 
200 
201 void JfifContainer::j_skip_input_data(JPEG::j_decompress_ptr cinfo,
202  long num_bytes)
203 {
204  jpeg_src_t *src = (jpeg_src_t*)cinfo->src;
205  if (num_bytes > 0) {
206  while ((size_t)num_bytes > src->pub.bytes_in_buffer) {
207  num_bytes -= src->pub.bytes_in_buffer;
208  j_fill_input_buffer(cinfo);
209  }
210  src->pub.next_input_byte += (size_t) num_bytes;
211  src->pub.bytes_in_buffer -= (size_t) num_bytes;
212  }
213 }
214 
215 
216 void JfifContainer::j_term_source(JPEG::j_decompress_ptr)
217 {
218 }
219 
221 {
222  if(!m_ifd) {
223  m_file->seek(0, SEEK_SET);
224 
225  uint16_t marker;
226  readUInt16(m_file, marker); // SOI
227  readUInt16(m_file, marker); // APP0
228  readUInt16(m_file, marker); // ignore
229 
230  char delim[7];
231  delim[6] = 0;
232  m_file->read(delim, 6);
233  if(memcmp(delim, "Exif\0\0", 6) == 0) {
234  size_t exif_offset = m_file->seek(0, SEEK_CUR);
235  m_ifd = new IfdFileContainer(
236  IO::Stream::Ptr(
237  std::make_shared<IO::StreamClone>(m_file, exif_offset)), 0);
238  }
239  }
240  return m_ifd;
241 }
242 
244 {
245  if(ifdContainer()) {
246  return m_ifd->setDirectory(0);
247  }
248  return IfdDir::Ref();
249 }
250 
251 IfdDir::Ref JfifContainer::getIfdDirAt(int idx)
252 {
253  if(ifdContainer()) {
254  return m_ifd->setDirectory(idx);
255  }
256  return IfdDir::Ref();
257 }
258 
259 
261 {
262  IfdDir::Ref main = mainIfd();
263  return main->getExifIFD();
264 }
265 
266 }
267 }
268 /*
269  Local Variables:
270  mode:c++
271  c-file-style:"stroustrup"
272  c-file-offsets:((innamespace . 0))
273  tab-width:2
274  c-basic-offset:2
275  indent-tabs-mode:nil
276  fill-column:80
277  End:
278 */
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard. I guess it failed.
Definition: arwfile.cpp:30
struct JPEG::jpeg_source_mgr pub
a JPEG container
virtual void setDimensions(uint32_t x, uint32_t y)
Definition: bitmapdata.cpp:169
Definition: trace.cpp:30