claw  1.9.0
jpeg_reader.cpp
Go to the documentation of this file.
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23  contact: julien.jorge@stuff-o-matic.com
24 */
30 #include <claw/graphic/jpeg.hpp>
31 
33 
34 #include <claw/assert.hpp>
35 #include <claw/exception.hpp>
36 
41 METHODDEF(void)
43 {
44  // nothing to do
45 }
46 
51 METHODDEF(boolean)
53 {
55  = (claw::graphic::jpeg::reader::source_manager*)cinfo->client_data;
56 
57  CLAW_PRECOND(&self->pub == cinfo->src);
58 
59  return self->fill_input_buffer();
60 }
61 
67 METHODDEF(void)
69  long num_bytes)
70 {
72  = (claw::graphic::jpeg::reader::source_manager*)cinfo->client_data;
73 
74  CLAW_PRECOND(&self->pub == cinfo->src);
75 
76  return self->skip_input_data(num_bytes);
77 }
78 
83 METHODDEF(void)
85 {
86  // nothing to do
87 }
88 
94  : m_input(is)
95  , m_buffer_size(1024)
96  , m_stream_position(0)
97 {
98  std::istream::pos_type pos = is.tellg();
99 
100  is.seekg(0, std::ios_base::end);
101  m_stream_size = is.tellg();
102 
103  is.seekg(pos, std::ios_base::beg);
104 
105  m_buffer = new JOCTET[m_buffer_size];
106  pub.bytes_in_buffer = 0;
107 }
108 
113 {
114  delete[] m_buffer;
115 }
116 
121 {
122  unsigned int n = std::min(m_buffer_size, m_stream_size - m_stream_position);
123  m_input.read((char*)m_buffer, n);
124 
125  pub.next_input_byte = m_buffer;
126  pub.bytes_in_buffer = n;
127 
128  m_stream_position += n;
129 
130  if(m_input)
131  return TRUE;
132  else
133  return FALSE;
134 }
135 
141  long num_bytes)
142 {
143  CLAW_PRECOND(num_bytes >= 0);
144 
145  if((size_t)num_bytes <= pub.bytes_in_buffer)
146  {
147  pub.next_input_byte += num_bytes;
148  pub.bytes_in_buffer -= num_bytes;
149  }
150  else
151  {
152  num_bytes -= pub.bytes_in_buffer;
153 
154  long div = num_bytes / m_buffer_size;
155  long rest = num_bytes % m_buffer_size;
156 
157  for(long i = 0; i != (div + 1); ++i)
158  fill_input_buffer();
159 
160  pub.next_input_byte += rest;
161  pub.bytes_in_buffer -= rest;
162  }
163 }
164 
169 claw::graphic::jpeg::reader::RGB_to_pixel32::operator()(
170  const JSAMPLE* pixel) const
171 {
172  rgba_pixel_8 result;
173 
174  result.components.alpha = 255;
175  result.components.red = pixel[0];
176  result.components.green = pixel[1];
177  result.components.blue = pixel[2];
178 
179  return result;
180 }
181 
186 claw::graphic::jpeg::reader::grayscale_to_pixel32::operator()(
187  const JSAMPLE* pixel) const
188 {
189  rgba_pixel_8 result;
190 
191  result.components.alpha = 255;
192  result.components.red = pixel[0];
193  result.components.green = pixel[0];
194  result.components.blue = pixel[0];
195 
196  return result;
197 }
198 
204  : m_image(img)
205 {}
206 
214  : m_image(img)
215 {
216  load(f);
217 }
218 
224 {
225  CLAW_PRECOND(!!f);
226 
227  std::istream::pos_type init_pos = f.tellg();
228 
229  try
230  {
231  read_from_file(f);
232  }
233  catch(...)
234  {
235  f.clear();
236  f.seekg(init_pos, std::ios_base::beg);
237  throw;
238  }
239 }
240 
245 void claw::graphic::jpeg::reader::read_from_file(std::istream& f)
246 {
247  source_manager infile(f);
248  jpeg_decompress_struct cinfo;
249  error_manager jerr;
250 
251  cinfo.err = jpeg_std_error(&jerr.pub);
252 
253  if(setjmp(jerr.setjmp_buffer))
254  throw CLAW_EXCEPTION(jerr.error_string);
255 
256  create_decompress_info(cinfo, infile);
257  jerr.pub.error_exit = jpeg__error_manager__error_exit;
258 
259  try
260  {
261  decompress(f, cinfo);
262  jpeg_destroy_decompress(&cinfo);
263  }
264  catch(...)
265  {
266  jpeg_destroy_decompress(&cinfo);
267  throw;
268  }
269 }
270 
276 void claw::graphic::jpeg::reader::decompress(std::istream& f,
277  jpeg_decompress_struct& cinfo)
278 {
279  error_manager jerr;
280  jpeg_error_mgr* jerr_saved = cinfo.err;
281 
282  cinfo.err = jpeg_std_error(&jerr.pub);
283  jerr.pub.error_exit = jpeg__error_manager__error_exit;
284 
285  if(setjmp(jerr.setjmp_buffer))
286  {
287  jpeg_abort_decompress(&cinfo);
288  throw CLAW_EXCEPTION(jerr.error_string);
289  }
290 
291  jpeg_read_header(&cinfo, TRUE);
292  jpeg_start_decompress(&cinfo);
293 
294  try
295  {
296  m_image.set_size(cinfo.image_width, cinfo.image_height);
297 
298  if(cinfo.out_color_components == 3)
299  read_data(cinfo, RGB_to_pixel32());
300  else if(cinfo.out_color_components == 1)
301  read_data(cinfo, grayscale_to_pixel32());
302  else
303  throw CLAW_EXCEPTION("invalid number of colors per channel");
304 
305  jpeg_finish_decompress(&cinfo);
306  }
307  catch(...)
308  {
309  jpeg_abort_decompress(&cinfo);
310  throw;
311  }
312 
313  cinfo.err = jerr_saved;
314 }
315 
321 void claw::graphic::jpeg::reader::create_decompress_info(
322  jpeg_decompress_struct& cinfo, source_manager& infile) const
323 {
324  jpeg_create_decompress(&cinfo);
325 
326  cinfo.src = &infile.pub;
327  cinfo.client_data = &infile;
328 
329  infile.pub.fill_input_buffer
331  infile.pub.skip_input_data
333  infile.pub.init_source = claw__graphic__jpeg__source_manager__init_source;
334  infile.pub.resync_to_restart = jpeg_resync_to_restart;
335  infile.pub.term_source = claw__graphic__jpeg__source_manager__term_source;
336 }
claw__graphic__jpeg__source_manager__fill_input_buffer(j_decompress_ptr cinfo)
Fill the input buffer with new data.
Definition: jpeg_reader.cpp:52
void load(std::istream &f)
Load an image from a jpeg file.
boolean fill_input_buffer()
Fill the input buffer with new data.
source_manager(std::istream &is)
Constructor.
Definition: jpeg_reader.cpp:93
claw__graphic__jpeg__source_manager__term_source(j_decompress_ptr cinfo)
Close the input stream.
Definition: jpeg_reader.cpp:84
A class for jpeg pictures.
struct jpeg_error_mgr pub
"public" fields, needed by the jpeg library.
Definition: jpeg.hpp:65
claw__graphic__jpeg__source_manager__skip_input_data(j_decompress_ptr cinfo, long num_bytes)
Skip some bytes in the input buffer.
Definition: jpeg_reader.cpp:68
std::string error_string
A comprehensive description of the error.
Definition: jpeg.hpp:71
struct claw::graphic::rgba_pixel::@15::@17 components
Component by component representation.
void jpeg__error_manager__error_exit(j_common_ptr cinfo)
Throw an exception when an error occurs in an internal jpeg processing.
jmp_buf setjmp_buffer
For return to caller.
Definition: jpeg.hpp:68
struct jpeg_source_mgr pub
"public" fields, needed by the jpeg library.
Definition: jpeg.hpp:98
Error handler that throw an exception instead of exiting the program.
Definition: jpeg.hpp:62
A simple class to use as exception with string message.
Source manager that allow us to read from a std::istream.
Definition: jpeg.hpp:87
Some assert macros to strengthen you code.
claw__graphic__jpeg__source_manager__init_source(j_decompress_ptr cinfo)
Initialize the input stream.
Definition: jpeg_reader.cpp:42
A class to deal with images.
Definition: image.hpp:50
Methods for the claw::graphic::jpeg::error_manager class.
reader(image &img)
Constructor.
#define CLAW_EXCEPTION(m)
Create an exception and add the name of the current function to the message.
Definition: exception.hpp:92
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition: assert.hpp:94
void skip_input_data(long num_bytes)
Skip some bytes in the input buffer.