claw  1.9.0
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@stuff-o-matic.com
24 */
30 #include <claw/graphic/png.hpp>
31 
32 #include <claw/assert.hpp>
33 #include <claw/exception.hpp>
34 
35 #include <limits>
36 
44  png_bytep data,
45  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 }
52 
58  : m_input(is)
59 {
60  CLAW_PRECOND(!!is);
61 }
62 
69  png_size_t length)
70 {
71  m_input.read((char*)data, length * sizeof(png_byte));
72 }
73 
74 const unsigned int claw::graphic::png::reader::s_rgba_pixel_size = 4;
75 
81  : m_image(img)
82 {}
83 
91  : m_image(img)
92 {
93  load(f);
94 }
95 
100 void claw::graphic::png::reader::load(std::istream& f)
101 {
102  CLAW_PRECOND(!!f);
103 
104  std::istream::pos_type init_pos = f.tellg();
105 
106  try
107  {
108  read_from_file(f);
109  }
110  catch(...)
111  {
112  f.clear();
113  f.seekg(init_pos, std::ios_base::beg);
114  throw;
115  }
116 }
117 
122 void claw::graphic::png::reader::read_from_file(std::istream& f)
123 {
124  source_manager infile(f);
125  png_structp png_ptr;
126  png_infop info_ptr;
127 
128  create_read_structures(png_ptr, info_ptr);
129 
130  if(setjmp(png_jmpbuf(png_ptr)))
131  {
132  /* If we get here, we had a problem reading the file */
133  /* Free all of the memory associated with the png_ptr and info_ptr */
134  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
135  throw CLAW_EXCEPTION("Invalid PNG file.");
136  }
137 
138  check_if_png(png_ptr, f);
139 
140  png_set_read_fn(png_ptr, (void*)&infile,
142 
143  png_read_info(png_ptr, info_ptr);
144 
145  png_set_strip_16(png_ptr);
146  png_set_expand_gray_1_2_4_to_8(png_ptr);
147  png_set_packing(png_ptr);
148 
149  png_set_tRNS_to_alpha(png_ptr);
150 
151  // transform palette index into RGB value
152  png_set_palette_to_rgb(png_ptr);
153 
154  // add an alpha value if none
155  png_set_filler(png_ptr,
156  std::numeric_limits<rgba_pixel_8::component_type>::max(),
157  PNG_FILLER_AFTER);
158 
159  png_read_update_info(png_ptr, info_ptr);
160 
161  read_image(png_ptr, info_ptr);
162 
163  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
164 }
165 
171 void claw::graphic::png::reader::check_if_png(png_structp png_ptr,
172  std::istream& f) const
173 {
174  CLAW_PRECOND(!!f);
175 
176  const unsigned int bytes_to_check = 8;
177  png_byte buffer[bytes_to_check];
178 
179  /* Read in some of the signature bytes */
180  f.read((char*)buffer, bytes_to_check * sizeof(png_byte));
181 
182  if((png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f)
183  throw CLAW_EXCEPTION("Not a PNG file.");
184 
185  png_set_sig_bytes(png_ptr, bytes_to_check);
186 }
187 
193 void claw::graphic::png::reader::read_image(png_structp png_ptr,
194  png_infop info_ptr)
195 {
196  CLAW_PRECOND(png_ptr);
197  CLAW_PRECOND(info_ptr);
198 
199  m_image.set_size(png_get_image_width(png_ptr, info_ptr),
200  png_get_image_height(png_ptr, info_ptr));
201 
202  if(png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE)
203  read_sequential_image(png_ptr, info_ptr);
204  else
205  read_interlaced_image(png_ptr, info_ptr,
206  png_set_interlace_handling(png_ptr));
207 }
208 
214 void claw::graphic::png::reader::read_sequential_image(png_structp png_ptr,
215  png_infop info_ptr)
216 {
217  CLAW_PRECOND(png_ptr);
218  CLAW_PRECOND(info_ptr);
219 
220  png_bytep data
221  = (png_bytep)png_malloc(png_ptr, s_rgba_pixel_size * m_image.width());
222  const png_byte color_type(png_get_color_type(png_ptr, info_ptr));
223 
224  try
225  {
226  for(unsigned int y = 0; y != m_image.height(); ++y)
227  {
228  png_read_row(png_ptr, data, NULL);
229  copy_pixel_line(color_type, data, y);
230  }
231  }
232  catch(...)
233  {
234  png_free(png_ptr, data);
235  throw;
236  }
237 
238  png_free(png_ptr, data);
239 }
240 
247 void claw::graphic::png::reader::read_interlaced_image(png_structp png_ptr,
248  png_infop info_ptr,
249  unsigned int passes)
250 {
251  CLAW_PRECOND(passes > 1);
252  CLAW_PRECOND(png_ptr);
253  CLAW_PRECOND(info_ptr);
254 
255  const unsigned int row_length = s_rgba_pixel_size * m_image.width();
256  png_bytepp data
257  = (png_bytepp)png_malloc(png_ptr, sizeof(png_bytep) * m_image.height());
258  unsigned int i = 0;
259  const png_byte color_type(png_get_color_type(png_ptr, info_ptr));
260 
261  try
262  {
263  for(i = 0; i != m_image.height(); ++i)
264  {
265  data[i] = (png_bytep)png_malloc(png_ptr, row_length);
266 
267  if(!data[i])
268  throw std::bad_alloc();
269 
270  copy_pixel_line(color_type, data[i], i);
271  }
272 
273  for(unsigned int p = 0; p != passes; ++p)
274  png_read_rows(png_ptr, data, NULL, m_image.height());
275 
276  for(unsigned int y = 0; y != m_image.height(); ++y)
277  copy_pixel_line(color_type, data[y], y);
278  }
279  catch(...)
280  {
281  for(unsigned int j = 0; j != i; ++j)
282  png_free(png_ptr, data[j]);
283 
284  png_free(png_ptr, data);
285  throw;
286  }
287 
288  for(i = 0; i != m_image.height(); ++i)
289  png_free(png_ptr, data[i]);
290 
291  png_free(png_ptr, data);
292 }
293 
300 void claw::graphic::png::reader::copy_pixel_line(png_byte color_type,
301  png_bytep data,
302  unsigned int y)
303 {
304  CLAW_PRECOND(data);
305  CLAW_PRECOND(y < m_image.height());
306 
307  if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
308  // There is two bytes for each pixel in the line: the color and the
309  // opacity.
310  for(unsigned int x = 0; x != m_image.width(); ++x, data += 2)
311  {
312  m_image[y][x].components.red = data[0];
313  m_image[y][x].components.green = data[0];
314  m_image[y][x].components.blue = data[0];
315  m_image[y][x].components.alpha = data[1];
316  }
317  else
318  // There is four bytes for each pixel in the line.
319  for(unsigned int x = 0; x != m_image.width();
320  ++x, data += s_rgba_pixel_size)
321  {
322  m_image[y][x].components.red = data[0];
323  m_image[y][x].components.green = data[1];
324  m_image[y][x].components.blue = data[2];
325  m_image[y][x].components.alpha = data[3];
326  }
327 }
328 
334 void claw::graphic::png::reader::create_read_structures(
335  png_structp& png_ptr, png_infop& info_ptr) const
336 {
337  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
338 
339  if(png_ptr)
340  {
341  info_ptr = png_create_info_struct(png_ptr);
342 
343  if(!info_ptr)
344  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
345  }
346 
347  if(!png_ptr || !info_ptr)
348  throw CLAW_EXCEPTION("Can't create PNG read structures.");
349 }
void load(std::istream &f)
Load an image from a png file.
Definition: png_reader.cpp:100
Source manager that allow us to read from a std::istream.
Definition: png.hpp:64
A class for png pictures.
void read(png_bytep data, png_size_t length)
Read data from the input stream.
Definition: png_reader.cpp:68
reader(image &img)
Constructor.
Definition: png_reader.cpp:80
A simple class to use as exception with string message.
source_manager(std::istream &is)
Constructor.
Definition: png_reader.cpp:57
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:43
Some assert macros to strengthen you code.
A class to deal with images.
Definition: image.hpp:50
#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