claw 1.9.0
 
Loading...
Searching...
No Matches
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
74const 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
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
122void 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
171void 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
193void 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
214void 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
247void 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
300void 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
334void 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}
Some assert macros to strengthen you code.
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition assert.hpp:94
image()
Constructor. Creates an image without datas.
Definition image.cpp:95
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:92
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:65
void read(png_bytep data, png_size_t length)
Read data from the input stream.
source_manager(std::istream &is)
Constructor.