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 
32 using namespace fawkes;
33 
34 namespace firevision {
35 #if 0 /* just to make Emacs auto-indent happy */
36 }
37 #endif
38 
39 /// @cond INTERNALS
40 class PNGReaderData
41 {
42  public:
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  */
59 PNGReader::PNGReader(const char *filename)
60 {
61  opened = false;
62  buffer = NULL;
63 
64  __d = setup_read(filename);
65 
66  opened = true;
67 }
68 
69 
70 PNGReaderData *
71 PNGReader::setup_read(const char *filename)
72 {
73  PNGReaderData *d = new PNGReaderData();
74  d->read = false;
75 
76  if ((d->infile = fopen(filename, "rb")) == NULL) {
77  throw Exception("Cannot open PNG file");
78  }
79 
80  d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
81 
82  if (d->png_ptr == NULL) {
83  fclose(d->infile);
84  throw Exception("Could not create PNG read struct");
85  }
86 
87  /* Allocate/initialize the memory for image information. REQUIRED. */
88  d->info_ptr = png_create_info_struct(d->png_ptr);
89  if (d->info_ptr == NULL) {
90  fclose(d->infile);
91  png_destroy_read_struct(&d->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
92  throw Exception("Could not create PNG info struct");
93  }
94 
95  /* Set error handling if you are using the setjmp/longjmp method (this is
96  * the normal method of doing things with libpng). REQUIRED unless you
97  * set up your own error handlers in the png_create_read_struct() earlier.
98  */
99  if (setjmp(png_jmpbuf(d->png_ptr))) {
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");
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) png_set_palette_to_rgb(d->png_ptr);
129 
130  /* Expand grayscale images into true RGB triplets */
131  if (color_type == PNG_COLOR_TYPE_GRAY) png_set_gray_to_rgb(d->png_ptr);
132 
133 
134  /* Tell libpng to handle the gamma conversion for you. The final call
135  * is a good guess for PC generated images, but it should be configurable
136  * by the user at run time by the user. It is strongly suggested that
137  * your application support gamma correction. */
138  int intent;
139  double screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly lit room */
140  if (png_get_sRGB(d->png_ptr, d->info_ptr, &intent)) {
141  png_set_gamma(d->png_ptr, screen_gamma, 0.45455);
142  } else {
143  double image_gamma;
144  if (png_get_gAMA(d->png_ptr, d->info_ptr, &image_gamma)) {
145  png_set_gamma(d->png_ptr, screen_gamma, image_gamma);
146  } else {
147  png_set_gamma(d->png_ptr, screen_gamma, 0.45455);
148  }
149  }
150 
151  /* Turn on interlace handling. REQUIRED if you are not using
152  * png_read_image(). To see how to handle interlacing passes,
153  * see the png_read_row() method below: */
154  d->number_passes = png_set_interlace_handling(d->png_ptr);
155 
156  /* Optional call to gamma correct and add the background to the palette
157  * and update info structure. REQUIRED if you are expecting libpng to
158  * update the palette for you (ie you selected such a transform above). */
159  png_read_update_info(d->png_ptr, d->info_ptr);
160 
161  return d;
162 }
163 
164 /** Destructor. */
165 PNGReader::~PNGReader()
166 {
167  fclose( __d->infile );
168  /* clean up after the read, and free any memory allocated - REQUIRED */
169  png_destroy_read_struct(&__d->png_ptr, &__d->info_ptr, (png_infopp)NULL);
170 
171  delete __d;
172 
173  opened = false;
174 }
175 
176 
177 void
178 PNGReader::set_buffer(unsigned char *yuv422planar_buffer)
179 {
180  buffer = yuv422planar_buffer;
181 }
182 
183 
184 colorspace_t
185 PNGReader::colorspace()
186 {
187  return YUV422_PLANAR;
188 }
189 
190 
191 unsigned int
192 PNGReader::pixel_width()
193 {
194  if ( opened ) {
195  return png_get_image_width(__d->png_ptr, __d->info_ptr);
196  } else {
197  return 0;
198  }
199 }
200 
201 
202 unsigned int
203 PNGReader::pixel_height()
204 {
205  if ( opened ) {
206  return png_get_image_height(__d->png_ptr, __d->info_ptr);
207  } else {
208  return 0;
209  }
210 }
211 
212 
213 void
214 PNGReader::read()
215 {
216  if ( buffer == NULL ) {
217  throw Exception("PNGReader::read: buffer == NULL");
218  }
219  if ( __d->read ) {
220  throw Exception("Can read PNG file only once.");
221  }
222  __d->read = true;
223 
224  png_bytep row_pointer;
225  row_pointer = (png_bytep)png_malloc(__d->png_ptr, png_get_rowbytes(__d->png_ptr, __d->info_ptr));
226 
227  unsigned int lheight = pixel_height();
228  unsigned int lwidth = pixel_width();
229 
230  for (int pass = 0; pass < __d->number_passes; ++pass) {
231  for (unsigned y = 0; y < lheight; ++y) {
232  png_read_rows(__d->png_ptr, &row_pointer, (png_bytepp)NULL, 1);
233  convert_line_rgb_to_yuv422planar( row_pointer, buffer, lwidth, lheight, 0, y );
234  }
235  }
236 
237  /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
238  png_read_end(__d->png_ptr, __d->info_ptr);
239  png_free(__d->png_ptr, row_pointer);
240 
241 }
242 
243 } // end namespace firevision
Fawkes library namespace.
Base class for exceptions in Fawkes.
Definition: exception.h:36