00001 /*!@file Raster/PngParser.C Parse png image files. */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Raster/PngParser.C $ 00035 // $Id: PngParser.C 11208 2009-05-20 02:03:21Z itti $ 00036 // 00037 00038 #ifdef INVT_HAVE_LIBPNG 00039 00040 #include "Raster/PngParser.H" 00041 00042 #include "Util/Assert.H" 00043 #include "Image/Image.H" 00044 #include "Image/Pixels.H" 00045 #include "Raster/GenericFrame.H" 00046 #include "Util/log.H" 00047 #include "Util/sformat.H" 00048 00049 #include <cerrno> 00050 #include <cstdio> 00051 #include <cstdlib> 00052 #include <png.h> 00053 00054 // ###################################################################### 00055 struct PngParser::Rep 00056 { 00057 Rep(const char* nm) : 00058 filename(nm), file(0), pngPtr(0), infoPtr(0), endPtr(0) 00059 {} 00060 00061 void close() 00062 { 00063 if (this->pngPtr != 0) 00064 { 00065 png_destroy_read_struct(this->pngPtr ? &this->pngPtr : 0, 00066 this->infoPtr ? &this->infoPtr : 0, 00067 this->endPtr ? &this->endPtr : 0); 00068 } 00069 00070 if (this->file != 0) 00071 { 00072 fclose(this->file); 00073 this->file = 0; 00074 } 00075 } 00076 00077 bool closed() const 00078 { 00079 return this->file == 0; 00080 } 00081 00082 void onError(const std::string& msg) 00083 { 00084 this->close(); 00085 if (errno == 0) 00086 { 00087 LFATAL("with file %s: %s\n", this->filename, msg.c_str()); 00088 } 00089 else 00090 { 00091 LFATAL("with file %s: %s\n [errno %d: %s]\n", 00092 this->filename, msg.c_str(), errno, strerror(errno)); 00093 } 00094 } 00095 00096 bool isGray() const 00097 { 00098 return this->colorType == PNG_COLOR_TYPE_GRAY 00099 || this->colorType == PNG_COLOR_TYPE_GRAY_ALPHA; 00100 } 00101 00102 bool isColor() const 00103 { 00104 return this->colorType == PNG_COLOR_TYPE_RGB 00105 || this->colorType == PNG_COLOR_TYPE_RGB_ALPHA 00106 || this->colorType == PNG_COLOR_TYPE_PALETTE; 00107 } 00108 00109 const char* filename; 00110 FILE* file; 00111 png_structp pngPtr; 00112 png_infop infoPtr; 00113 png_infop endPtr; 00114 int width; 00115 int height; 00116 int bitDepth; 00117 png_byte colorType; 00118 int rowBytes; 00119 int numChannels; 00120 00121 }; 00122 00123 // ###################################################################### 00124 PngParser::PngParser(const char* filename) 00125 : 00126 rep(new Rep(filename)) 00127 { 00128 errno = 0; 00129 rep->file = fopen(filename, "rb"); 00130 if (rep->file == 0) rep->onError("couldn't open file for png reading"); 00131 00132 const size_t nheader = 8; 00133 png_byte header[nheader]; 00134 00135 if (fread(header, 1, nheader, rep->file) != nheader) rep->onError("short read on png file header"); 00136 00137 int is_png = !png_sig_cmp(header, 0, nheader); 00138 if (!is_png) rep->onError("file was not a png image file"); 00139 00140 rep->pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 00141 if (rep->pngPtr == 0) rep->onError("png_create_read_struct failed"); 00142 00143 rep->infoPtr = png_create_info_struct(rep->pngPtr); 00144 if (rep->infoPtr == 0) rep->onError("png_create_info_struct failed"); 00145 00146 rep->endPtr = png_create_info_struct(rep->pngPtr); 00147 if (rep->endPtr == 0) rep->onError("png_create_info_struct failed"); 00148 00149 png_init_io(rep->pngPtr, rep->file); 00150 00151 png_set_sig_bytes(rep->pngPtr, nheader); 00152 00153 png_read_info(rep->pngPtr, rep->infoPtr); 00154 00155 rep->bitDepth = png_get_bit_depth(rep->pngPtr, rep->infoPtr); 00156 00157 rep->colorType = png_get_color_type(rep->pngPtr, rep->infoPtr); 00158 00159 if (rep->bitDepth == 16) 00160 png_set_strip_16(rep->pngPtr); 00161 else if (rep->bitDepth < 8 && (rep->colorType == PNG_COLOR_TYPE_GRAY)) 00162 png_set_gray_1_2_4_to_8(rep->pngPtr); 00163 else if (rep->bitDepth != 8 && (rep->colorType != PNG_COLOR_TYPE_PALETTE)) 00164 rep->onError(sformat("invalid bit-depth(%d)/color-mode(%d) " 00165 "combination", rep->bitDepth, rep->colorType)); 00166 00167 // Strip out the alpha channel, if present 00168 if (rep->colorType & PNG_COLOR_MASK_ALPHA) 00169 png_set_strip_alpha(rep->pngPtr); 00170 00171 if (rep->colorType & PNG_COLOR_MASK_PALETTE) 00172 png_set_palette_to_rgb(rep->pngPtr); 00173 00174 // This must come after any+all transformations are specified 00175 png_read_update_info(rep->pngPtr, rep->infoPtr); 00176 00177 // These calls must come after png_read_update_info, so that we get 00178 // values that reflect any transformations 00179 rep->width = png_get_image_width(rep->pngPtr, rep->infoPtr); 00180 rep->height = png_get_image_height(rep->pngPtr, rep->infoPtr); 00181 00182 rep->rowBytes = png_get_rowbytes(rep->pngPtr, rep->infoPtr); 00183 00184 rep->numChannels = png_get_channels(rep->pngPtr, rep->infoPtr); 00185 00186 ASSERT(rep->rowBytes = rep->width*rep->numChannels); 00187 00188 // run-time mmx PNG optimizations (nate) 00189 #if defined(HAVE_PNG_ASM_FLAGS) 00190 const png_uint_32 flags = png_get_asm_flags(rep->pngPtr); 00191 const png_uint_32 mask = 00192 png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE); 00193 png_set_asm_flags(rep->pngPtr, flags | mask); 00194 #endif 00195 } 00196 00197 // ###################################################################### 00198 PngParser::~PngParser() 00199 { 00200 rep->close(); 00201 00202 delete rep; 00203 } 00204 00205 // ###################################################################### 00206 GenericFrameSpec PngParser::getFrameSpec() const 00207 { 00208 GenericFrameSpec result; 00209 00210 if (rep->isGray()) result.nativeType = GenericFrame::GRAY_U8; 00211 else if (rep->isColor()) result.nativeType = GenericFrame::RGB_U8; 00212 else rep->onError("unsupported image type (neither grayscale nor RGB)"); 00213 00214 result.videoFormat = VIDFMT_AUTO; 00215 result.videoByteSwap = false; 00216 result.dims = Dims(rep->width, rep->height); 00217 result.floatFlags = 0; 00218 00219 return result; 00220 } 00221 00222 // ###################################################################### 00223 std::string PngParser::getComments() const 00224 { return "PNG comments not currently supported"; } 00225 00226 // ###################################################################### 00227 uint PngParser::getTagCount() const 00228 { return 0; } 00229 00230 // ###################################################################### 00231 bool PngParser::getTag(uint tag, std::string &name, std::string &value) const 00232 { return false; } 00233 00234 // ###################################################################### 00235 GenericFrame PngParser::getFrame() 00236 { 00237 if (rep->isGray()) return GenericFrame(parseGray()); 00238 else if (rep->isColor()) return GenericFrame(parseRGB()); 00239 // else... 00240 rep->onError("unsupported image type (neither grayscale nor RGB)"); 00241 /* can't happen */ return GenericFrame(); 00242 } 00243 00244 // ###################################################################### 00245 Image<byte> PngParser::parseGray() 00246 { 00247 ASSERT(!rep->closed()); 00248 ASSERT(rep->isGray()); 00249 ASSERT(rep->rowBytes == rep->width); 00250 00251 errno = 0; 00252 00253 Image<byte> result(rep->width, rep->height, NO_INIT); 00254 00255 png_bytep* row_pointers = new png_bytep[rep->height]; 00256 00257 for (int i = 0; i < rep->height; ++i) 00258 { 00259 row_pointers[i] = (png_bytep) (result.getArrayPtr() + rep->width*i); 00260 } 00261 00262 png_read_image(rep->pngPtr, row_pointers); 00263 00264 png_read_end(rep->pngPtr, rep->endPtr); 00265 00266 delete [] row_pointers; 00267 00268 rep->close(); 00269 00270 return result; 00271 } 00272 00273 // ###################################################################### 00274 Image<PixRGB<byte> > PngParser::parseRGB() 00275 { 00276 ASSERT(!rep->closed()); 00277 ASSERT(rep->isColor()); 00278 ASSERT(rep->rowBytes == rep->width*3); 00279 00280 errno = 0; 00281 00282 Image<PixRGB<byte> > result(rep->width, rep->height, NO_INIT); 00283 00284 png_bytep* row_pointers = new png_bytep[rep->height]; 00285 00286 for (int i = 0; i < rep->height; ++i) 00287 { 00288 row_pointers[i] = (png_bytep) (result.getArrayPtr() + rep->width*i); 00289 } 00290 00291 png_read_image(rep->pngPtr, row_pointers); 00292 00293 png_read_end(rep->pngPtr, rep->endPtr); 00294 00295 delete [] row_pointers; 00296 00297 rep->close(); 00298 00299 return result; 00300 } 00301 00302 #endif // INVT_HAVE_LIBPNG 00303 00304 // ###################################################################### 00305 /* So things look consistent in everyone's emacs... */ 00306 /* Local Variables: */ 00307 /* indent-tabs-mode: nil */ 00308 /* End: */