JpegParser.C

Go to the documentation of this file.
00001 /*!@file Raster/JpegParser.C Parser for jpeg image files */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the 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 at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Raster/JpegParser.C $
00035 // $Id: JpegParser.C 10439 2008-11-17 06:31:45Z itti $
00036 //
00037 
00038 #ifndef RASTER_JPEGPARSER_C_DEFINED
00039 #define RASTER_JPEGPARSER_C_DEFINED
00040 
00041 #include "Raster/JpegParser.H"
00042 
00043 #include "Raster/GenericFrame.H"
00044 #include "rutz/error.h"
00045 #include "rutz/sfmt.h"
00046 #include "rutz/trace.h"
00047 
00048 #include <csetjmp>
00049 #include <cstdio>
00050 
00051 #ifdef INVT_HAVE_LIBJPEG
00052 
00053 // WARNING: jpeglib.h is braindead in a couple ways -- (1) it doesn't
00054 // have the extern "C" to be c++-friendly, like every other modern C
00055 // header does, so we have to provide the extern "C" ourselves, and
00056 // (2) it's not self-contained -- it will bomb out if we don't
00057 // explicitly #include <stdio.h> and <stdlib.h> before jpeglib.h; (3)
00058 // on darwin it defines HAVE_STDLIB_H which conflicts with our
00059 // definition:
00060 #include <stdlib.h>
00061 #include <stdio.h>
00062 #undef HAVE_STDLIB_H
00063 extern "C"
00064 {
00065 #include <jpeglib.h>
00066 }
00067 
00068 namespace
00069 {
00070   struct jpeg_aux
00071   {
00072     FILE* infile;
00073     jmp_buf* jmp_state;
00074   };
00075 
00076   void cleanup(jpeg_decompress_struct* cinfo)
00077   {
00078     jpeg_aux* aux = static_cast<jpeg_aux*>(cinfo->client_data);
00079     if (aux->infile != 0)
00080       fclose(aux->infile);
00081     jpeg_destroy_decompress(cinfo);
00082   }
00083 
00084   void jpeg_error_exit(j_common_ptr cinfo)
00085   {
00086     // Since we longjmp out of here, DON'T use any C++ objects that
00087     // need to have destructors run!
00088 
00089     cinfo->err->output_message(cinfo);
00090 
00091     jpeg_aux* aux = static_cast<jpeg_aux*>(cinfo->client_data);
00092     longjmp(*(aux->jmp_state), 1);
00093   }
00094 }
00095 
00096 #define SETJMP_TRY(statement)                            \
00097 do {                                                     \
00098   if (setjmp(state) == 0)                                \
00099     {                                                    \
00100       statement;                                         \
00101     }                                                    \
00102   else                                                   \
00103     {                                                    \
00104       LFATAL("%s failed for file %s", #statement, filename);    \
00105     }                                                    \
00106 } while (0)
00107 
00108 #endif
00109 
00110 struct JpegParser::Impl
00111 {
00112   Impl(const char* fname);
00113 
00114   Image<PixRGB<byte> > rgb;
00115   Image<byte> gray;
00116 };
00117 
00118 // ######################################################################
00119 
00120 JpegParser::Impl::Impl(const char* filename)
00121 {
00122 #ifndef INVT_HAVE_LIBJPEG
00123   LFATAL("jpeg support is disabled since libjpeg was not found at configure time");
00124 #else
00125   GVX_TRACE(__PRETTY_FUNCTION__);
00126 
00127   if (BITS_IN_JSAMPLE != 8)
00128     {
00129       throw rutz::error("jpeg library must be built for 8 bits-per-sample",
00130                         SRC_POS);
00131     }
00132 
00133   jmp_buf state;
00134 
00135   // 1. Allocate and initialize the JPEG decompression object
00136   jpeg_decompress_struct cinfo;
00137   jpeg_error_mgr jerr;
00138 
00139   jpeg_aux aux;
00140   aux.infile = 0;
00141   aux.jmp_state = &state;
00142   cinfo.client_data = static_cast<void*>(&aux);
00143 
00144   cinfo.err = jpeg_std_error(&jerr);
00145   cinfo.err->error_exit = &jpeg_error_exit;
00146 
00147   SETJMP_TRY(jpeg_create_decompress(&cinfo));
00148 
00149   // 2. Specify the source of the compressed data (i.e., the input file)
00150   aux.infile = fopen(filename, "rb");
00151 
00152   if (aux.infile == 0)
00153     {
00154       throw rutz::error(rutz::sfmt("couldn't open '%s' for reading",
00155                                    filename), SRC_POS);
00156     }
00157 
00158 
00159   SETJMP_TRY(jpeg_stdio_src(&cinfo, aux.infile));
00160 
00161   // 3. Call jpeg_read_header() to obtain image info
00162   SETJMP_TRY(jpeg_read_header(&cinfo, TRUE));
00163 
00164   // 4. Set parameters for decompression
00165 
00166   // 5. Start decompression
00167   SETJMP_TRY(jpeg_start_decompress(&cinfo));
00168 
00169   // cinfo.output_width
00170   // cinfo.output_height
00171   // cinfo.out_color_components
00172   // cinfo.output_components
00173 
00174   // 6. Read scanlines
00175 
00176   switch (cinfo.output_components)
00177     {
00178     case 1:
00179       {
00180         this->gray = Image<byte>(cinfo.output_width,
00181                                  cinfo.output_height,
00182                                  NO_INIT);
00183 
00184         while (cinfo.output_scanline < cinfo.output_height)
00185           {
00186             JSAMPLE* dest =
00187               this->gray.getArrayPtr()
00188               + cinfo.output_scanline * this->gray.getWidth();
00189 
00190             SETJMP_TRY(jpeg_read_scanlines(&cinfo,
00191                                            &dest,
00192                                            /* max lines */ 1));
00193           }
00194       }
00195       break;
00196     case 3:
00197       {
00198         this->rgb = Image<PixRGB<byte> >(cinfo.output_width,
00199                                          cinfo.output_height,
00200                                          NO_INIT);
00201 
00202         while (cinfo.output_scanline < cinfo.output_height)
00203           {
00204             JSAMPLE* dest =
00205               reinterpret_cast<JSAMPLE*>
00206               (this->rgb.getArrayPtr()
00207                + cinfo.output_scanline * this->rgb.getWidth());
00208 
00209             SETJMP_TRY(jpeg_read_scanlines(&cinfo,
00210                                            &dest,
00211                                            /* max lines */ 1));
00212           }
00213       }
00214       break;
00215     default:
00216       LFATAL("invalid number of jpeg components (%d)",
00217              cinfo.output_components);
00218       break;
00219     }
00220 
00221   // 7. finish decompression
00222   SETJMP_TRY(jpeg_finish_decompress(&cinfo));
00223 
00224   // 8. cleanup
00225   cleanup(&cinfo);
00226 #endif
00227 }
00228 
00229 // ######################################################################
00230 
00231 JpegParser::JpegParser(const char* fname)
00232   :
00233   rep(new Impl(fname))
00234 {
00235   ASSERT(rep->rgb.initialized() || rep->gray.initialized());
00236 }
00237 
00238 // ######################################################################
00239 
00240 JpegParser::~JpegParser()
00241 {
00242   delete rep;
00243 }
00244 
00245 GenericFrameSpec JpegParser::getFrameSpec() const
00246 {
00247   GenericFrameSpec result;
00248 
00249   if      (rep->rgb.initialized())
00250     {
00251       result.nativeType = GenericFrame::RGB_U8;
00252       result.dims = rep->rgb.getDims();
00253     }
00254   else if (rep->gray.initialized())
00255     {
00256       result.nativeType = GenericFrame::GRAY_U8;
00257       result.dims = rep->gray.getDims();
00258     }
00259   else
00260     ASSERT(0);
00261 
00262   result.videoFormat = VIDFMT_AUTO;
00263   result.videoByteSwap = false;
00264   result.floatFlags = 0;
00265 
00266   return result;
00267 }
00268 
00269 // ######################################################################
00270 
00271 std::string JpegParser::getComments() const
00272 {
00273   return std::string();
00274 }
00275 
00276 // ######################################################################
00277 
00278 uint JpegParser::getTagCount() const
00279 {
00280   return 0;
00281 }
00282 
00283 // ######################################################################
00284 
00285 bool JpegParser::getTag(uint tag, std::string &name, std::string &value) const
00286 {
00287   return false;
00288 }
00289 
00290 // ######################################################################
00291 
00292 GenericFrame JpegParser::getFrame()
00293 {
00294   if (rep->rgb.initialized())
00295     return GenericFrame(rep->rgb);
00296 
00297   // else...
00298   ASSERT(rep->gray.initialized());
00299   return GenericFrame(rep->gray);
00300 }
00301 
00302 // ######################################################################
00303 /* So things look consistent in everyone's emacs... */
00304 /* Local Variables: */
00305 /* mode: c++ */
00306 /* indent-tabs-mode: nil */
00307 /* End: */
00308 
00309 #endif // RASTER_JPEGPARSER_C_DEFINED
Generated on Sun May 8 08:41:16 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3