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/*----------------------------------------------------------------------------*/
83const 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/*----------------------------------------------------------------------------*/
114void 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/*----------------------------------------------------------------------------*/
137void 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/*----------------------------------------------------------------------------*/
187void 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/*----------------------------------------------------------------------------*/
210void 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/*----------------------------------------------------------------------------*/
232void 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/*----------------------------------------------------------------------------*/
266void 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/*----------------------------------------------------------------------------*/
319void
320claw::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/*----------------------------------------------------------------------------*/
352void 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()
Some assert macros to strengthen you code.
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition assert.hpp:98
A class to deal with images.
Definition image.hpp:50
void load(std::istream &f)
Load an image from a png file.
reader(image &img)
Constructor.
A simple class to use as exception with string message.
#define CLAW_EXCEPTION(m)
Create an exception and add the name of the current function to the message.
Definition exception.hpp:90
A class for png pictures.
void claw__graphic__png__source_manager__read(png_structp png_ptr, png_bytep data, png_size_t length)
Read data from the input stream.
Source manager that allow us to read from a std::istream.
Definition png.hpp:66
void read(png_bytep data, png_size_t length)
Read data from the input stream.
source_manager(std::istream &is)
Constructor.