PngParser.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:41:16 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3