Claw  1.7.3
png_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@gamned.org
24 */
30 #include <claw/png.hpp>
31 
32 #include <claw/exception.hpp>
33 #include <claw/assert.hpp>
34 
35 #include <limits>
36 
37 /*----------------------------------------------------------------------------*/
45 ( png_structp png_ptr, png_bytep data, png_size_t length )
46 {
48  (claw::graphic::png::reader::source_manager*)png_get_io_ptr(png_ptr);
49 
50  self->read(data, length);
51 } // claw__graphic__png__source_manager__read()
52 
53 
54 
55 
56 /*----------------------------------------------------------------------------*/
62  : m_input(is)
63 {
64  CLAW_PRECOND( !!is );
65 } // png::reader::source_manager::source_manager()
66 
67 /*----------------------------------------------------------------------------*/
74 ( png_bytep data, png_size_t length )
75 {
76  m_input.read( (char*)data, length * sizeof(png_byte) );
77 } // png::reader::source_manager::read()
78 
79 
80 
81 
82 /*----------------------------------------------------------------------------*/
83 const unsigned int claw::graphic::png::reader::s_rgba_pixel_size = 4;
84 
85 /*----------------------------------------------------------------------------*/
91  : m_image( img )
92 {
93 
94 } // png::reader::reader()
95 
96 /*----------------------------------------------------------------------------*/
104  : m_image( img )
105 {
106  load(f);
107 } // png::reader::reader()
108 
109 /*----------------------------------------------------------------------------*/
114 void claw::graphic::png::reader::load( std::istream& f )
115 {
116  CLAW_PRECOND( !!f );
117 
118  std::istream::pos_type init_pos = f.tellg();
119 
120  try
121  {
122  read_from_file(f);
123  }
124  catch(...)
125  {
126  f.clear();
127  f.seekg( init_pos, std::ios_base::beg );
128  throw;
129  }
130 } // png::reader::load()
131 
132 /*----------------------------------------------------------------------------*/
137 void claw::graphic::png::reader::read_from_file( std::istream& f )
138 {
139  source_manager infile(f);
140  png_structp png_ptr;
141  png_infop info_ptr;
142 
143  create_read_structures(png_ptr, info_ptr);
144 
145  if (setjmp(png_jmpbuf(png_ptr)))
146  {
147  /* If we get here, we had a problem reading the file */
148  /* Free all of the memory associated with the png_ptr and info_ptr */
149  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
150  throw CLAW_EXCEPTION("Invalid PNG file.");
151  }
152 
153  check_if_png( png_ptr, f );
154 
155  png_set_read_fn( png_ptr, (void *)&infile,
157 
158  png_set_strip_16(png_ptr);
159  png_set_expand_gray_1_2_4_to_8(png_ptr);
160  png_set_packing(png_ptr);
161 
162  // transform palette index into RGB value
163  png_set_palette_to_rgb(png_ptr);
164 
165  // add an alpha value if none
166  png_set_filler( png_ptr,
167  std::numeric_limits<rgba_pixel_8::component_type>::max(),
168  PNG_FILLER_AFTER );
169 
170  png_read_info(png_ptr, info_ptr);
171  read_image( png_ptr, info_ptr );
172 
173  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
174 } // png::reader::read_from_file()
175 
176 /*----------------------------------------------------------------------------*/
182 void claw::graphic::png::reader::check_if_png
183 ( png_structp png_ptr, std::istream& f ) const
184 {
185  CLAW_PRECOND( !!f );
186 
187  const unsigned int bytes_to_check = 8;
188  png_byte buffer[bytes_to_check];
189 
190  /* Read in some of the signature bytes */
191  f.read( (char*)buffer, bytes_to_check * sizeof(png_byte) );
192 
193  if ( (png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f )
194  throw CLAW_EXCEPTION( "Not a PNG file." );
195 
196  png_set_sig_bytes(png_ptr, bytes_to_check);
197 } // png::reader::check_if_png()
198 
199 /*----------------------------------------------------------------------------*/
205 void claw::graphic::png::reader::read_image
206 ( png_structp png_ptr, png_infop info_ptr )
207 {
208  CLAW_PRECOND( png_ptr );
209  CLAW_PRECOND( info_ptr );
210 
211  m_image.set_size( png_get_image_width(png_ptr, info_ptr),
212  png_get_image_height(png_ptr, info_ptr) );
213 
214  if ( png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE )
215  read_sequential_image(png_ptr, info_ptr);
216  else
217  read_interlaced_image( png_ptr, info_ptr,
218  png_set_interlace_handling(png_ptr) );
219 } // png::reader::read_image()
220 
221 /*----------------------------------------------------------------------------*/
227 void claw::graphic::png::reader::read_sequential_image
228 ( png_structp png_ptr, png_infop info_ptr )
229 {
230  CLAW_PRECOND( png_ptr );
231  CLAW_PRECOND( info_ptr );
232 
233  png_bytep data =
234  (png_bytep)png_malloc( png_ptr, s_rgba_pixel_size * m_image.width() );
235 
236  try
237  {
238  for (unsigned int y=0; y!=m_image.height(); ++y)
239  {
240  png_read_row(png_ptr, data, NULL);
241  copy_pixel_line( data, y );
242  }
243  }
244  catch(...)
245  {
246  png_free(png_ptr, data);
247  throw;
248  }
249 
250  png_free(png_ptr, data);
251 } // png::reader::read_sequential_image()
252 
253 /*----------------------------------------------------------------------------*/
260 void claw::graphic::png::reader::read_interlaced_image
261 ( png_structp png_ptr, png_infop info_ptr, unsigned int passes )
262 {
263  CLAW_PRECOND( passes > 1 );
264  CLAW_PRECOND( png_ptr );
265  CLAW_PRECOND( info_ptr );
266 
267  const unsigned int row_length = s_rgba_pixel_size * m_image.width();
268  png_bytepp data =
269  (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() );
270  unsigned int i=0;
271 
272  try
273  {
274  for (i=0; i!=m_image.height(); ++i)
275  {
276  data[i] = (png_bytep)png_malloc( png_ptr, row_length );
277 
278  if (!data[i])
279  throw std::bad_alloc();
280 
281  copy_pixel_line( data[i], i );
282  }
283 
284  for (unsigned int p=0; p!=passes; ++p)
285  png_read_rows( png_ptr, data, NULL, m_image.height() );
286 
287  for (unsigned int y=0; y!=m_image.height(); ++y)
288  copy_pixel_line( data[y], y );
289  }
290  catch(...)
291  {
292  for(unsigned int j=0; j!=i; ++j)
293  png_free(png_ptr, data[j]);
294 
295  png_free(png_ptr, data);
296  throw;
297  }
298 
299  for(i=0; i!=m_image.height(); ++i)
300  png_free(png_ptr, data[i]);
301 
302  png_free(png_ptr, data);
303 } // png::reader::read_interlaced_image()
304 
305 /*----------------------------------------------------------------------------*/
311 void
312 claw::graphic::png::reader::copy_pixel_line( png_bytep data, unsigned int y )
313 {
314  CLAW_PRECOND( data );
315  CLAW_PRECOND( y < m_image.height() );
316 
317  // four bytes for each pixel in the line
318  for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size)
319  {
320  m_image[y][x].components.red = data[0];
321  m_image[y][x].components.green = data[1];
322  m_image[y][x].components.blue = data[2];
323  m_image[y][x].components.alpha = data[3];
324  }
325 } // png::reader::copy_pixel_line()
326 
327 /*----------------------------------------------------------------------------*/
333 void claw::graphic::png::reader::create_read_structures
334 ( png_structp& png_ptr, png_infop& info_ptr ) const
335 {
336  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
337 
338  if (png_ptr)
339  {
340  info_ptr = png_create_info_struct(png_ptr);
341 
342  if (!info_ptr)
343  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
344  }
345 
346  if (!png_ptr || !info_ptr)
347  throw CLAW_EXCEPTION("Can't create PNG read structures.");
348 } // png::reader::create_read_structures()