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 
35 using namespace fawkes;
36 
37 namespace firevision {
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 PNGReaderData *
70 PNGReader::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. */
166 PNGReader::~PNGReader()
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 
177 void
178 PNGReader::set_buffer(unsigned char *yuv422planar_buffer)
179 {
180  buffer = yuv422planar_buffer;
181 }
182 
183 colorspace_t
184 PNGReader::colorspace()
185 {
186  return YUV422_PLANAR;
187 }
188 
189 unsigned int
190 PNGReader::pixel_width()
191 {
192  if (opened) {
193  return png_get_image_width(d_->png_ptr, d_->info_ptr);
194  } else {
195  return 0;
196  }
197 }
198 
199 unsigned int
200 PNGReader::pixel_height()
201 {
202  if (opened) {
203  return png_get_image_height(d_->png_ptr, d_->info_ptr);
204  } else {
205  return 0;
206  }
207 }
208 
209 void
210 PNGReader::read()
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
Fawkes library namespace.
Base class for exceptions in Fawkes.
Definition: exception.h:35