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_read_info(png_ptr, info_ptr);
159 
160  png_set_strip_16(png_ptr);
161  png_set_expand_gray_1_2_4_to_8(png_ptr);
162  png_set_packing(png_ptr);
163 
164  png_set_tRNS_to_alpha(png_ptr);
165 
166  // transform palette index into RGB value
167  png_set_palette_to_rgb(png_ptr);
168 
169  // add an alpha value if none
170  png_set_filler( png_ptr,
171  std::numeric_limits<rgba_pixel_8::component_type>::max(),
172  PNG_FILLER_AFTER );
173 
174  png_read_update_info(png_ptr, info_ptr);
175 
176  read_image( png_ptr, info_ptr );
177 
178  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
179 } // png::reader::read_from_file()
180 
181 /*----------------------------------------------------------------------------*/
187 void claw::graphic::png::reader::check_if_png
188 ( png_structp png_ptr, std::istream& f ) const
189 {
190  CLAW_PRECOND( !!f );
191 
192  const unsigned int bytes_to_check = 8;
193  png_byte buffer[bytes_to_check];
194 
195  /* Read in some of the signature bytes */
196  f.read( (char*)buffer, bytes_to_check * sizeof(png_byte) );
197 
198  if ( (png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f )
199  throw CLAW_EXCEPTION( "Not a PNG file." );
200 
201  png_set_sig_bytes(png_ptr, bytes_to_check);
202 } // png::reader::check_if_png()
203 
204 /*----------------------------------------------------------------------------*/
210 void claw::graphic::png::reader::read_image
211 ( png_structp png_ptr, png_infop info_ptr )
212 {
213  CLAW_PRECOND( png_ptr );
214  CLAW_PRECOND( info_ptr );
215 
216  m_image.set_size( png_get_image_width(png_ptr, info_ptr),
217  png_get_image_height(png_ptr, info_ptr) );
218 
219  if ( png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE )
220  read_sequential_image(png_ptr, info_ptr);
221  else
222  read_interlaced_image( png_ptr, info_ptr,
223  png_set_interlace_handling(png_ptr) );
224 } // png::reader::read_image()
225 
226 /*----------------------------------------------------------------------------*/
232 void claw::graphic::png::reader::read_sequential_image
233 ( png_structp png_ptr, png_infop info_ptr )
234 {
235  CLAW_PRECOND( png_ptr );
236  CLAW_PRECOND( info_ptr );
237 
238  png_bytep data =
239  (png_bytep)png_malloc( png_ptr, s_rgba_pixel_size * m_image.width() );
240  const png_byte color_type( png_get_color_type(png_ptr, info_ptr) );
241 
242  try
243  {
244  for (unsigned int y=0; y!=m_image.height(); ++y)
245  {
246  png_read_row(png_ptr, data, NULL);
247  copy_pixel_line( color_type, data, y );
248  }
249  }
250  catch(...)
251  {
252  png_free(png_ptr, data);
253  throw;
254  }
255 
256  png_free(png_ptr, data);
257 } // png::reader::read_sequential_image()
258 
259 /*----------------------------------------------------------------------------*/
266 void claw::graphic::png::reader::read_interlaced_image
267 ( png_structp png_ptr, png_infop info_ptr, unsigned int passes )
268 {
269  CLAW_PRECOND( passes > 1 );
270  CLAW_PRECOND( png_ptr );
271  CLAW_PRECOND( info_ptr );
272 
273  const unsigned int row_length = s_rgba_pixel_size * m_image.width();
274  png_bytepp data =
275  (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() );
276  unsigned int i=0;
277  const png_byte color_type( png_get_color_type(png_ptr, info_ptr) );
278 
279  try
280  {
281  for (i=0; i!=m_image.height(); ++i)
282  {
283  data[i] = (png_bytep)png_malloc( png_ptr, row_length );
284 
285  if (!data[i])
286  throw std::bad_alloc();
287 
288  copy_pixel_line( color_type, data[i], i );
289  }
290 
291  for (unsigned int p=0; p!=passes; ++p)
292  png_read_rows( png_ptr, data, NULL, m_image.height() );
293 
294  for (unsigned int y=0; y!=m_image.height(); ++y)
295  copy_pixel_line( color_type, data[y], y );
296  }
297  catch(...)
298  {
299  for(unsigned int j=0; j!=i; ++j)
300  png_free(png_ptr, data[j]);
301 
302  png_free(png_ptr, data);
303  throw;
304  }
305 
306  for(i=0; i!=m_image.height(); ++i)
307  png_free(png_ptr, data[i]);
308 
309  png_free(png_ptr, data);
310 } // png::reader::read_interlaced_image()
311 
312 /*----------------------------------------------------------------------------*/
319 void
320 claw::graphic::png::reader::copy_pixel_line
321 ( png_byte color_type, png_bytep data, unsigned int y )
322 {
323  CLAW_PRECOND( data );
324  CLAW_PRECOND( y < m_image.height() );
325 
326  if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
327  // There is two bytes for each pixel in the line: the color and the opacity.
328  for (unsigned int x=0; x!=m_image.width(); ++x, data += 2)
329  {
330  m_image[y][x].components.red = data[0];
331  m_image[y][x].components.green = data[0];
332  m_image[y][x].components.blue = data[0];
333  m_image[y][x].components.alpha = data[1];
334  }
335  else
336  // There is four bytes for each pixel in the line.
337  for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size)
338  {
339  m_image[y][x].components.red = data[0];
340  m_image[y][x].components.green = data[1];
341  m_image[y][x].components.blue = data[2];
342  m_image[y][x].components.alpha = data[3];
343  }
344 } // png::reader::copy_pixel_line()
345 
346 /*----------------------------------------------------------------------------*/
352 void claw::graphic::png::reader::create_read_structures
353 ( png_structp& png_ptr, png_infop& info_ptr ) const
354 {
355  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
356 
357  if (png_ptr)
358  {
359  info_ptr = png_create_info_struct(png_ptr);
360 
361  if (!info_ptr)
362  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
363  }
364 
365  if (!png_ptr || !info_ptr)
366  throw CLAW_EXCEPTION("Can't create PNG read structures.");
367 } // png::reader::create_read_structures()
unsigned int height() const
Gets image&#39;s height.
Definition: image.cpp:159
void load(std::istream &f)
Load an image from a png file.
Definition: png_reader.cpp:114
Source manager that allow us to read from a std::istream.
Definition: png.hpp:65
#define CLAW_EXCEPTION(m)
Create an exception and add the name of the current function to the message.
Definition: exception.hpp:90
unsigned int width() const
Gets image&#39;s width.
Definition: image.cpp:147
A class for png pictures.
void read(png_bytep data, png_size_t length)
Read data from the input stream.
Definition: png_reader.cpp:74
reader(image &img)
Constructor.
Definition: png_reader.cpp:90
A simple class to use as exception with string message.
source_manager(std::istream &is)
Constructor.
Definition: png_reader.cpp:61
void claw__graphic__png__source_manager__read(png_structp png_ptr, png_bytep data, png_size_t length)
Read data from the input stream.
Definition: png_reader.cpp:45
Some assert macros to strengthen you code.
A class to deal with images.
Definition: image.hpp:49
void set_size(unsigned int w, unsigned int h)
Set a new size to the image.
Definition: image.cpp:363
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition: assert.hpp:98