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