Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * png.cpp - PNG Reader 00004 * 00005 * Created: Thu Apr 03 12:56:56 2008 00006 * Copyright 2005-2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <core/exception.h> 00025 #include <fvutils/readers/png.h> 00026 #include <fvutils/color/rgbyuv.h> 00027 00028 #include <cstdio> 00029 #include <cstdlib> 00030 #include <png.h> 00031 00032 using namespace fawkes; 00033 00034 namespace firevision { 00035 #if 0 /* just to make Emacs auto-indent happy */ 00036 } 00037 #endif 00038 00039 /// @cond INTERNALS 00040 class PNGReaderData 00041 { 00042 public: 00043 FILE *infile; 00044 png_structp png_ptr; 00045 png_infop info_ptr; 00046 int number_passes; 00047 bool read; 00048 }; 00049 /// @endcond 00050 00051 /** @class PNGReader <fvutils/readers/png.h> 00052 * PNG file reader. 00053 * @author Tim Niemueller 00054 */ 00055 00056 /** Constructor. 00057 * @param filename file to read 00058 */ 00059 PNGReader::PNGReader(const char *filename) 00060 { 00061 opened = false; 00062 buffer = NULL; 00063 00064 __d = setup_read(filename); 00065 00066 opened = true; 00067 } 00068 00069 00070 PNGReaderData * 00071 PNGReader::setup_read(const char *filename) 00072 { 00073 PNGReaderData *d = new PNGReaderData(); 00074 d->read = false; 00075 00076 if ((d->infile = fopen(filename, "rb")) == NULL) { 00077 throw Exception("Cannot open PNG file"); 00078 } 00079 00080 d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 00081 00082 if (d->png_ptr == NULL) { 00083 fclose(d->infile); 00084 throw Exception("Could not create PNG read struct"); 00085 } 00086 00087 /* Allocate/initialize the memory for image information. REQUIRED. */ 00088 d->info_ptr = png_create_info_struct(d->png_ptr); 00089 if (d->info_ptr == NULL) { 00090 fclose(d->infile); 00091 png_destroy_read_struct(&d->png_ptr, (png_infopp)NULL, (png_infopp)NULL); 00092 throw Exception("Could not create PNG info struct"); 00093 } 00094 00095 /* Set error handling if you are using the setjmp/longjmp method (this is 00096 * the normal method of doing things with libpng). REQUIRED unless you 00097 * set up your own error handlers in the png_create_read_struct() earlier. 00098 */ 00099 if (setjmp(png_jmpbuf(d->png_ptr))) { 00100 /* Free all of the memory associated with the png_ptr and info_ptr */ 00101 png_destroy_read_struct(&d->png_ptr, &d->info_ptr, (png_infopp)NULL); 00102 fclose(d->infile); 00103 /* If we get here, we had a problem reading the file */ 00104 throw Exception("Could not read PNG file"); 00105 } 00106 00107 /* Set up the input control if you are using standard C streams */ 00108 png_init_io(d->png_ptr, d->infile); 00109 00110 /* The call to png_read_info() gives us all of the information from the 00111 * PNG file before the first IDAT (image data chunk). REQUIRED */ 00112 png_read_info(d->png_ptr, d->info_ptr); 00113 00114 /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 00115 png_set_strip_16(d->png_ptr); 00116 00117 /* Strip alpha bytes from the input data without combining with the 00118 * background (not recommended). */ 00119 png_set_strip_alpha(d->png_ptr); 00120 00121 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 00122 * byte into separate bytes (useful for paletted and grayscale images). */ 00123 png_set_packing(d->png_ptr); 00124 00125 png_byte color_type = png_get_color_type(d->png_ptr, d->info_ptr); 00126 00127 /* Expand paletted colors into true RGB triplets */ 00128 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(d->png_ptr); 00129 00130 /* Expand grayscale images into true RGB triplets */ 00131 if (color_type == PNG_COLOR_TYPE_GRAY) png_set_gray_to_rgb(d->png_ptr); 00132 00133 00134 /* Tell libpng to handle the gamma conversion for you. The final call 00135 * is a good guess for PC generated images, but it should be configurable 00136 * by the user at run time by the user. It is strongly suggested that 00137 * your application support gamma correction. */ 00138 int intent; 00139 double screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly lit room */ 00140 if (png_get_sRGB(d->png_ptr, d->info_ptr, &intent)) { 00141 png_set_gamma(d->png_ptr, screen_gamma, 0.45455); 00142 } else { 00143 double image_gamma; 00144 if (png_get_gAMA(d->png_ptr, d->info_ptr, &image_gamma)) { 00145 png_set_gamma(d->png_ptr, screen_gamma, image_gamma); 00146 } else { 00147 png_set_gamma(d->png_ptr, screen_gamma, 0.45455); 00148 } 00149 } 00150 00151 /* Turn on interlace handling. REQUIRED if you are not using 00152 * png_read_image(). To see how to handle interlacing passes, 00153 * see the png_read_row() method below: */ 00154 d->number_passes = png_set_interlace_handling(d->png_ptr); 00155 00156 /* Optional call to gamma correct and add the background to the palette 00157 * and update info structure. REQUIRED if you are expecting libpng to 00158 * update the palette for you (ie you selected such a transform above). */ 00159 png_read_update_info(d->png_ptr, d->info_ptr); 00160 00161 return d; 00162 } 00163 00164 /** Destructor. */ 00165 PNGReader::~PNGReader() 00166 { 00167 fclose( __d->infile ); 00168 /* clean up after the read, and free any memory allocated - REQUIRED */ 00169 png_destroy_read_struct(&__d->png_ptr, &__d->info_ptr, (png_infopp)NULL); 00170 00171 delete __d; 00172 00173 opened = false; 00174 } 00175 00176 00177 void 00178 PNGReader::set_buffer(unsigned char *yuv422planar_buffer) 00179 { 00180 buffer = yuv422planar_buffer; 00181 } 00182 00183 00184 colorspace_t 00185 PNGReader::colorspace() 00186 { 00187 return YUV422_PLANAR; 00188 } 00189 00190 00191 unsigned int 00192 PNGReader::pixel_width() 00193 { 00194 if ( opened ) { 00195 return png_get_image_width(__d->png_ptr, __d->info_ptr); 00196 } else { 00197 return 0; 00198 } 00199 } 00200 00201 00202 unsigned int 00203 PNGReader::pixel_height() 00204 { 00205 if ( opened ) { 00206 return png_get_image_height(__d->png_ptr, __d->info_ptr); 00207 } else { 00208 return 0; 00209 } 00210 } 00211 00212 00213 void 00214 PNGReader::read() 00215 { 00216 if ( buffer == NULL ) { 00217 throw Exception("PNGReader::read: buffer == NULL"); 00218 } 00219 if ( __d->read ) { 00220 throw Exception("Can read PNG file only once."); 00221 } 00222 __d->read = true; 00223 00224 png_bytep row_pointer; 00225 row_pointer = (png_bytep)png_malloc(__d->png_ptr, png_get_rowbytes(__d->png_ptr, __d->info_ptr)); 00226 00227 unsigned int lheight = pixel_height(); 00228 unsigned int lwidth = pixel_width(); 00229 00230 for (int pass = 0; pass < __d->number_passes; ++pass) { 00231 for (unsigned y = 0; y < lheight; ++y) { 00232 png_read_rows(__d->png_ptr, &row_pointer, (png_bytepp)NULL, 1); 00233 convert_line_rgb_to_yuv422planar( row_pointer, buffer, lwidth, lheight, 0, y ); 00234 } 00235 } 00236 00237 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 00238 png_read_end(__d->png_ptr, __d->info_ptr); 00239 png_free(__d->png_ptr, row_pointer); 00240 00241 } 00242 00243 } // end namespace firevision