libopenraw
jfifcontainer.cpp
1 /*
2  * libopenraw - jfifcontainer.h
3  *
4  * Copyright (C) 2006-2007 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 <cstdio>
24 
25 namespace JPEG {
26  /*
27  * The extern "C" below is REQUIRED for libjpeg-mmx-dev
28  * as found on debian because some people have this installed.
29  */
30  extern "C" {
31 #include <jpeglib.h>
32  }
33 }
34 
35 #include <string.h>
36 #include <libopenraw++/bitmapdata.h>
37 #include "io/stream.h"
38 #include "trace.h"
39 #include "jfifcontainer.h"
40 
41 namespace OpenRaw {
42 
43  using namespace Debug;
44 
45  namespace Internals {
46 
49  #define BUF_SIZE 1024
50 
51  typedef struct {
52  struct JPEG::jpeg_source_mgr pub;
53  JFIFContainer * self;
54  off_t offset;
55  JPEG::JOCTET* buf;
56  } jpeg_src_t;
57 
58  JFIFContainer::JFIFContainer(IO::Stream *_file, off_t offset)
59  : RawContainer(_file, offset),
60  m_cinfo(), m_jerr(),
61  m_headerLoaded(false)
62  {
63  setEndian(ENDIAN_BIG);
64  /* this is a hack because jpeg_create_decompress is
65  * implemented as a Macro
66  */
67  using namespace JPEG;
68 
69  m_cinfo.err = JPEG::jpeg_std_error(&m_jerr);
70  m_jerr.error_exit = &j_error_exit;
71  JPEG::jpeg_create_decompress(&m_cinfo);
72 
73  /* inspired by jdatasrc.c */
74 
75  jpeg_src_t *src = (jpeg_src_t *)
76  (*m_cinfo.mem->alloc_small)((JPEG::j_common_ptr)&m_cinfo,
77  JPOOL_PERMANENT,
78  sizeof(jpeg_src_t));
79  m_cinfo.src = (JPEG::jpeg_source_mgr*)src;
80  src->pub.init_source = j_init_source;
81  src->pub.fill_input_buffer = j_fill_input_buffer;
82  src->pub.skip_input_data = j_skip_input_data;
83  src->pub.resync_to_restart = JPEG::jpeg_resync_to_restart;
84  src->pub.term_source = j_term_source;
85  src->self = this;
86  src->pub.bytes_in_buffer = 0;
87  src->pub.next_input_byte = NULL;
88  src->buf = (JPEG::JOCTET*)(*m_cinfo.mem->alloc_small)
89  ((JPEG::j_common_ptr)&m_cinfo,
90  JPOOL_PERMANENT,
91  BUF_SIZE * sizeof(JPEG::JOCTET));
92  }
93 
95  {
96  JPEG::jpeg_destroy_decompress(&m_cinfo);
97  }
98 
99 
100  bool JFIFContainer::getDimensions(uint32_t &x, uint32_t &y)
101  {
102  if(!m_headerLoaded) {
103  if (_loadHeader() == 0) {
104  Trace(DEBUG1) << "load header failed\n";
105  return false;
106  }
107  }
108  x = m_cinfo.output_width;
109  y = m_cinfo.output_height;
110  return true;
111  }
112 
113 
114  bool JFIFContainer::getDecompressedData(BitmapData &data)
115  {
116  if(!m_headerLoaded) {
117  if (_loadHeader() == 0) {
118  Trace(DEBUG1) << "load header failed\n";
119  return false;
120  }
121  }
122  if (::setjmp(m_jpegjmp) != 0) {
123  return false;
124  }
125  JPEG::jpeg_start_decompress(&m_cinfo);
126  int row_size = m_cinfo.output_width * m_cinfo.output_components;
127  char *dataPtr = (char*)data.allocData(row_size * m_cinfo.output_height);
128  char *currentPtr = dataPtr;
129  JPEG::JSAMPARRAY buffer = (*m_cinfo.mem->alloc_sarray)((JPEG::j_common_ptr)&m_cinfo,
130  JPOOL_IMAGE, row_size,
131  1);
132  while (m_cinfo.output_scanline < m_cinfo.output_height) {
133  jpeg_read_scanlines(&m_cinfo, buffer, 1);
134  memcpy(currentPtr, buffer, row_size);
135  currentPtr += row_size;
136  }
137  data.setDimensions(m_cinfo.output_width, m_cinfo.output_height);
138 
139  JPEG::jpeg_finish_decompress(&m_cinfo);
140  return true;
141  }
142 
143 
144  int JFIFContainer::_loadHeader()
145  {
146  int ret = 0;
147  if (::setjmp(m_jpegjmp) == 0) {
148  ret = JPEG::jpeg_read_header(&m_cinfo, TRUE);
149  //Trace(DEBUG1) << "jpeg_read_header " << ret << "\n";
150 
151  JPEG::jpeg_calc_output_dimensions(&m_cinfo);
152  }
153  m_headerLoaded = (ret == 1);
154  return ret;
155  }
156 
157 
158  void JFIFContainer::j_error_exit(JPEG::j_common_ptr cinfo)
159  {
160  (*cinfo->err->output_message) (cinfo);
161  JFIFContainer *self = ((jpeg_src_t *)(((JPEG::j_decompress_ptr)cinfo)->src))->self;
162  ::longjmp(self->m_jpegjmp, 1);
163  }
164 
165  void JFIFContainer::j_init_source(JPEG::j_decompress_ptr)
166  {
167  }
168 
169 
170  JPEG::boolean
171  JFIFContainer::j_fill_input_buffer(JPEG::j_decompress_ptr cinfo)
172  {
173  jpeg_src_t *src = (jpeg_src_t*)cinfo->src;
174  JFIFContainer *self = src->self;
175  int n = self->file()->read(src->buf, BUF_SIZE * sizeof(*src->buf));
176  if (n >= 0) {
177  src->pub.next_input_byte = src->buf;
178  src->pub.bytes_in_buffer = n;
179  }
180  else {
181  src->pub.next_input_byte = NULL;
182  src->pub.bytes_in_buffer = 0;
183  }
184  return TRUE;
185  }
186 
187 
188  void JFIFContainer::j_skip_input_data(JPEG::j_decompress_ptr cinfo,
189  long num_bytes)
190  {
191  jpeg_src_t *src = (jpeg_src_t*)cinfo->src;
192  if (num_bytes > 0) {
193  while ((size_t)num_bytes > src->pub.bytes_in_buffer) {
194  num_bytes -= src->pub.bytes_in_buffer;
195  j_fill_input_buffer(cinfo);
196  }
197  src->pub.next_input_byte += (size_t) num_bytes;
198  src->pub.bytes_in_buffer -= (size_t) num_bytes;
199  }
200  }
201 
202 
203  void JFIFContainer::j_term_source(JPEG::j_decompress_ptr)
204  {
205  }
206 
207 
208  }
209 }
struct JPEG::jpeg_source_mgr pub
virtual int read(void *buf, size_t count)=0
base virtual class for IO
Definition: stream.h:40