Fawkes API Fawkes Development Version
png.cpp
1
2/***************************************************************************
3 * png.cpp - PNG Reader
4 *
5 * Created: Thu Apr 03 12:56:56 2008
6 * Copyright 2005-2008 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/exception.h>
25#include <fvutils/color/rgbyuv.h>
26#include <fvutils/readers/png.h>
27
28#include <cerrno>
29#include <cstdio>
30#include <cstdlib>
31#include <cstring>
32#include <png.h>
33#include <string>
34
35using namespace fawkes;
36
37namespace firevision {
38
39/// @cond INTERNALS
40class PNGReaderData
41{
42public:
43 FILE * infile;
44 png_structp png_ptr;
45 png_infop info_ptr;
46 int number_passes;
47 bool read;
48};
49/// @endcond
50
51/** @class PNGReader <fvutils/readers/png.h>
52 * PNG file reader.
53 * @author Tim Niemueller
54 */
55
56/** Constructor.
57 * @param filename file to read
58 */
59PNGReader::PNGReader(const char *filename)
60{
61 opened = false;
62 buffer = NULL;
63
64 d_ = setup_read(filename);
65
66 opened = true;
67}
68
69PNGReaderData *
70PNGReader::setup_read(const char *filename)
71{
72 PNGReaderData *d = new PNGReaderData();
73 d->read = false;
74
75 if ((d->infile = fopen(filename, "rb")) == NULL) {
76 throw Exception("Cannot open PNG file %s: %s", filename, ::strerror(errno));
77 }
78
79 d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
80
81 if (d->png_ptr == NULL) {
82 fclose(d->infile);
83 throw Exception("Could not create PNG read struct");
84 }
85
86 /* Allocate/initialize the memory for image information. REQUIRED. */
87 d->info_ptr = png_create_info_struct(d->png_ptr);
88 if (d->info_ptr == NULL) {
89 fclose(d->infile);
90 png_destroy_read_struct(&d->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
91 throw Exception("Could not create PNG info struct");
92 }
93
94 /* Set error handling if you are using the setjmp/longjmp method (this is
95 * the normal method of doing things with libpng). REQUIRED unless you
96 * set up your own error handlers in the png_create_read_struct() earlier.
97 */
98 if (setjmp(png_jmpbuf(d->png_ptr))) {
99 std::string err(::strerror(errno));
100 /* Free all of the memory associated with the png_ptr and info_ptr */
101 png_destroy_read_struct(&d->png_ptr, &d->info_ptr, (png_infopp)NULL);
102 fclose(d->infile);
103 /* If we get here, we had a problem reading the file */
104 throw Exception("Could not read PNG file %s: %s", filename, err.c_str());
105 }
106
107 /* Set up the input control if you are using standard C streams */
108 png_init_io(d->png_ptr, d->infile);
109
110 /* The call to png_read_info() gives us all of the information from the
111 * PNG file before the first IDAT (image data chunk). REQUIRED */
112 png_read_info(d->png_ptr, d->info_ptr);
113
114 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
115 png_set_strip_16(d->png_ptr);
116
117 /* Strip alpha bytes from the input data without combining with the
118 * background (not recommended). */
119 png_set_strip_alpha(d->png_ptr);
120
121 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
122 * byte into separate bytes (useful for paletted and grayscale images). */
123 png_set_packing(d->png_ptr);
124
125 png_byte color_type = png_get_color_type(d->png_ptr, d->info_ptr);
126
127 /* Expand paletted colors into true RGB triplets */
128 if (color_type == PNG_COLOR_TYPE_PALETTE)
129 png_set_palette_to_rgb(d->png_ptr);
130
131 /* Expand grayscale images into true RGB triplets */
132 if (color_type == PNG_COLOR_TYPE_GRAY)
133 png_set_gray_to_rgb(d->png_ptr);
134
135 /* Tell libpng to handle the gamma conversion for you. The final call
136 * is a good guess for PC generated images, but it should be configurable
137 * by the user at run time by the user. It is strongly suggested that
138 * your application support gamma correction. */
139 int intent;
140 double screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly lit room */
141 if (png_get_sRGB(d->png_ptr, d->info_ptr, &intent)) {
142 png_set_gamma(d->png_ptr, screen_gamma, 0.45455);
143 } else {
144 double image_gamma;
145 if (png_get_gAMA(d->png_ptr, d->info_ptr, &image_gamma)) {
146 png_set_gamma(d->png_ptr, screen_gamma, image_gamma);
147 } else {
148 png_set_gamma(d->png_ptr, screen_gamma, 0.45455);
149 }
150 }
151
152 /* Turn on interlace handling. REQUIRED if you are not using
153 * png_read_image(). To see how to handle interlacing passes,
154 * see the png_read_row() method below: */
155 d->number_passes = png_set_interlace_handling(d->png_ptr);
156
157 /* Optional call to gamma correct and add the background to the palette
158 * and update info structure. REQUIRED if you are expecting libpng to
159 * update the palette for you (ie you selected such a transform above). */
160 png_read_update_info(d->png_ptr, d->info_ptr);
161
162 return d;
163}
164
165/** Destructor. */
167{
168 fclose(d_->infile);
169 /* clean up after the read, and free any memory allocated - REQUIRED */
170 png_destroy_read_struct(&d_->png_ptr, &d_->info_ptr, (png_infopp)NULL);
171
172 delete d_;
173
174 opened = false;
175}
176
177void
178PNGReader::set_buffer(unsigned char *yuv422planar_buffer)
179{
180 buffer = yuv422planar_buffer;
181}
182
183colorspace_t
185{
186 return YUV422_PLANAR;
187}
188
189unsigned int
191{
192 if (opened) {
193 return png_get_image_width(d_->png_ptr, d_->info_ptr);
194 } else {
195 return 0;
196 }
197}
198
199unsigned int
201{
202 if (opened) {
203 return png_get_image_height(d_->png_ptr, d_->info_ptr);
204 } else {
205 return 0;
206 }
207}
208
209void
211{
212 if (buffer == NULL) {
213 throw Exception("PNGReader::read: buffer == NULL");
214 }
215 if (d_->read) {
216 throw Exception("Can read PNG file only once.");
217 }
218 d_->read = true;
219
220 png_bytep row_pointer;
221 row_pointer = (png_bytep)png_malloc(d_->png_ptr, png_get_rowbytes(d_->png_ptr, d_->info_ptr));
222
223 unsigned int lheight = pixel_height();
224 unsigned int lwidth = pixel_width();
225
226 for (int pass = 0; pass < d_->number_passes; ++pass) {
227 for (unsigned y = 0; y < lheight; ++y) {
228 png_read_rows(d_->png_ptr, &row_pointer, (png_bytepp)NULL, 1);
229 convert_line_rgb_to_yuv422planar(row_pointer, buffer, lwidth, lheight, 0, y);
230 }
231 }
232
233 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
234 png_read_end(d_->png_ptr, d_->info_ptr);
235 png_free(d_->png_ptr, row_pointer);
236}
237
238} // end namespace firevision
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void set_buffer(unsigned char *yuv422planar_buffer)
Set buffer that the read image should be written to.
Definition: png.cpp:178
virtual unsigned int pixel_height()
Get height of read image in pixels.
Definition: png.cpp:200
virtual ~PNGReader()
Destructor.
Definition: png.cpp:166
PNGReader(const char *filename)
Constructor.
Definition: png.cpp:59
virtual colorspace_t colorspace()
Get colorspace from the just read image.
Definition: png.cpp:184
virtual void read()
Read data from file.
Definition: png.cpp:210
virtual unsigned int pixel_width()
Get width of read image in pixels.
Definition: png.cpp:190
Fawkes library namespace.