ImageReader.cpp
Go to the documentation of this file.
00001 #include "puma2config.h"
00002 #include "ImageReader.h"
00003 #include "PumaException.h"
00004 #include "PumaMessages.h"
00005 
00006 #include <cstdio>
00007 #include <cerrno>
00008 #include <string>
00009 
00010 using namespace std;
00011 using namespace puma2;
00012 
00013 #ifdef HAVE_LIBPNG
00014 # include <png.h>
00015 static bool readImageGrayPNG ( GrayLevelImage8 &img, FILE *fp );
00016 static bool readImageColorPNG ( ColorImageRGB8 &img, FILE *fp );
00017 #endif
00018 
00019 #ifdef HAVE_LIBJPEG
00020 //extern "C"
00021 //{
00022 # include <jpeglib.h>
00023   // special in memory jpeg lib src, see jmemsrc.c
00024   void jpeg_memory_src ( j_decompress_ptr cinfo, JOCTET * ptr, size_t numBytes );
00025 //};
00026 
00027 static bool readImageGrayJPEG ( GrayLevelImage8 &img, FILE *fp );
00028 static bool readImageColorJPEGFromFile ( ColorImageRGB8 &img, FILE *fp );
00029 static bool readImageColorJPEGFromMemory ( ColorImageRGB8 &img, JOCTET * ptr, size_t numBytes );
00030 static bool readImageColorJPEG_generic ( ColorImageRGB8 &img, struct jpeg_decompress_struct &cinfo );
00031 #endif
00032 
00033 #ifdef HAVE_IMAGEMAGICK
00034 #  include <Magick++/Image.h>
00035 static bool readImageGrayMagick ( GrayLevelImage8 &img, string filename );
00036 static bool readImageGrayMagick ( GrayLevelImage16 &img, string filename );
00037 static bool readImageColorMagick ( ColorImageRGB8 &img, string filename );
00038 static bool readImageColorMagick ( ColorImageRGBa8 &img, string filename );
00039 #endif
00040 
00041 // forward declarations
00042 static bool readImageGrayBuiltinPNM ( GrayLevelImage8 &img, FILE *fp );
00043 static bool readImageColorBuiltinPNM ( ColorImageRGB8 &img, FILE *fp );
00044 
00045 
00046 bool ImageReader::readImage ( GrayLevelImage8 &img, string filename )
00047 {
00048   const int lookAheadLength = 8;
00049   byte magicChars [lookAheadLength];
00050   int returnValue;
00051   bool success = false;
00052 
00053   FILE *filePointer = fopen ( filename.c_str(), "rb" ); // "b" for binary mode on non-Unix
00054   if ( filePointer == NULL )
00055   {
00056     string msg ( "cannot open file: " );
00057     msg += filename;
00058     msg += strerror ( errno );
00059     throw PumaException ( PumaException::intolerable, msg );
00060     return false;
00061   }
00062 
00063   returnValue = fread ( magicChars, lookAheadLength, 1, filePointer );
00064   if ( returnValue != 1 )
00065   {
00066     string msg ( "can't read from file: " );
00067     msg += strerror ( errno );
00068     throw PumaException ( PumaException::intolerable, msg );
00069   }
00070   rewind ( filePointer );
00071   if ( ftell ( filePointer ) != 0 )
00072   {
00073     string msg ( "can't peek into file start, rewind failed: " );
00074     msg += strerror ( errno );
00075     throw PumaException ( PumaException::intolerable, msg );
00076   }
00077 
00078 #ifdef HAVE_LIBPNG
00079   if ( png_sig_cmp ( magicChars, 0, lookAheadLength ) == 0 )
00080   {
00081     success = readImageGrayPNG ( img, filePointer );
00082   }
00083   else
00084 #endif
00085 #ifdef HAVE_LIBJPEG
00086     if ( ( magicChars[0] == 0xff ) && ( magicChars[1] == 0xd8 ) )
00087     {
00088       success = readImageGrayJPEG ( img, filePointer );
00089     }
00090     else
00091 #endif
00092       if ( ( magicChars[0] == 'P' )
00093            && ( ( magicChars[1] >= '1' ) && ( magicChars[1] <= '6' ) )
00094            && ( ( magicChars[2] == ' ' ) || ( magicChars[2] == '\n' ) || ( magicChars[2] == '\r' ) || ( magicChars[2] == '\t' ) )
00095          )
00096       {
00097         success = readImageGrayBuiltinPNM ( img, filePointer );
00098       }
00099   fclose ( filePointer );
00100 
00101 #ifdef HAVE_IMAGEMAGICK
00102   if ( ! success ) // ImageMagick++ has no method to read from a file pointer :-(
00103   {
00104     success = readImageGrayMagick ( img, filename );
00105   }
00106 #endif
00107   if ( ! success )
00108   {
00109     string msg ( "unknown/unsupported image format, can't read file." );
00110     throw PumaException ( PumaException::intolerable, msg );
00111     success = false;
00112   }
00113   return success;
00114 }
00115 
00116 bool ImageReader::readImage ( GrayLevelImage16 &img, string filename )
00117 {
00118   const int lookAheadLength = 8;
00119   byte magicChars [lookAheadLength];
00120   int returnValue;
00121   bool success = false;
00122 
00123   FILE *filePointer = fopen ( filename.c_str(), "rb" ); // "b" for binary mode on non-Unix
00124   if ( filePointer == NULL )
00125   {
00126     string msg ( "cannot open file: " );
00127     msg += filename;
00128     msg += strerror ( errno );
00129     throw PumaException ( PumaException::intolerable, msg );
00130     return false;
00131   }
00132 
00133   returnValue = fread ( magicChars, lookAheadLength, 1, filePointer );
00134   if ( returnValue != 1 )
00135   {
00136     string msg ( "can't read from file: " );
00137     msg += strerror ( errno );
00138     throw PumaException ( PumaException::intolerable, msg );
00139   }
00140   rewind ( filePointer );
00141   if ( ftell ( filePointer ) != 0 )
00142   {
00143     string msg ( "can't peek into file start, rewind failed: " );
00144     msg += strerror ( errno );
00145     throw PumaException ( PumaException::intolerable, msg );
00146   }
00147 
00148 #ifdef HAVE_IMAGEMAGICK
00149   if ( ! success ) // ImageMagick++ has no method to read from a file pointer :-(
00150   {
00151     success = readImageGrayMagick ( img, filename );
00152   }
00153 #endif
00154   if ( ! success )
00155   {
00156     string msg ( "unknown/unsupported image format, can't read file." );
00157     throw PumaException ( PumaException::intolerable, msg );
00158     success = false;
00159   }
00160   return success;
00161 }
00162 
00163 bool ImageReader::readImage ( ColorImageRGB8 &img, string filename )
00164 {
00165   const int lookAheadLength = 8;
00166   byte magicChars [lookAheadLength];
00167   int returnValue;
00168   bool success = false;
00169 
00170   FILE *filePointer = fopen ( filename.c_str(), "rb" ); // "b" for binary mode on non-Unix
00171   if ( filePointer == NULL )
00172   {
00173     string msg ( "cannot open file: " );
00174     msg += filename;
00175     msg += strerror ( errno );
00176     throw PumaException ( PumaException::intolerable, msg );
00177     return false;
00178   }
00179 
00180   returnValue = fread ( magicChars, lookAheadLength, 1, filePointer );
00181   if ( returnValue != 1 )
00182   {
00183     string msg ( "can't read from file: " );
00184     msg += strerror ( errno );
00185     throw PumaException ( PumaException::intolerable, msg );
00186   }
00187   rewind ( filePointer );
00188   if ( ftell ( filePointer ) != 0 )
00189   {
00190     string msg ( "can't peek into file start, rewind failed: " );
00191     msg += strerror ( errno );
00192     throw PumaException ( PumaException::intolerable, msg );
00193   }
00194 
00195 #ifdef HAVE_LIBPNG
00196   if ( png_sig_cmp ( magicChars, 0, lookAheadLength ) == 0 )
00197   {
00198     success = readImageColorPNG ( img, filePointer );
00199   }
00200   else
00201 #endif
00202 #ifdef HAVE_LIBJPEG
00203     if ( ( magicChars[0] == 0xff ) && ( magicChars[1] == 0xd8 ) )
00204     {
00205       success = readImageColorJPEGFromFile ( img, filePointer );
00206     }
00207     else
00208 #endif
00209       if ( ( magicChars[0] == 'P' )
00210            && ( ( magicChars[1] >= '1' ) && ( magicChars[1] <= '6' ) )
00211            && ( ( magicChars[2] == ' ' ) || ( magicChars[2] == '\n' ) || ( magicChars[2] == '\r' ) || ( magicChars[2] == '\t' ) )
00212          )
00213       {
00214         success = readImageColorBuiltinPNM ( img, filePointer );
00215       }
00216   fclose ( filePointer );
00217 
00218 #ifdef HAVE_IMAGEMAGICK
00219   if ( ! success ) // ImageMagick++ has no method to read from a file pointer :-(
00220   {
00221     success = readImageColorMagick ( img, filename );
00222   }
00223 #endif
00224   if ( ! success )
00225   {
00226     string msg ( "unknown image format, can't read file '" );
00227     msg += filename + "'.";
00228     throw PumaException ( PumaException::intolerable, msg );
00229     success = false;
00230   }
00231   return success;
00232 }
00233 
00234 bool ImageReader::loadJPEGImage ( ColorImageRGB8  &img, byte* ptr, size_t numBytes )
00235 {
00236 #ifdef HAVE_LIBJPEG
00237   if ( ptr == NULL )
00238   {
00239     string msg ( "can't load data from NULL pointer" );
00240     throw PumaException ( PumaException::intolerable, msg );
00241     return false;
00242   }
00243   return readImageColorJPEGFromMemory ( img, ptr, numBytes );
00244 #else
00245   string msg ( "libpuma2 compiled without libjpeg support, loadJPEGImage() not available" );
00246   throw PumaException ( PumaException::intolerable, msg );
00247 #endif
00248 }
00249 
00250 bool ImageReader::readImage ( ColorImageRGBa8 &img, string filename )
00251 {
00252   const int lookAheadLength = 8;
00253   byte magicChars [lookAheadLength];
00254   int returnValue;
00255   bool success = false;
00256 
00257   FILE *filePointer = fopen ( filename.c_str(), "rb" ); // "b" for binary mode on non-Unix
00258   if ( filePointer == NULL )
00259   {
00260     string msg ( "cannot open file: " );
00261     msg += filename;
00262     msg += strerror ( errno );
00263     throw PumaException ( PumaException::intolerable, msg );
00264     return false;
00265   }
00266 
00267   returnValue = fread ( magicChars, lookAheadLength, 1, filePointer );
00268   if ( returnValue != 1 )
00269   {
00270     string msg ( "can't read from file: " );
00271     msg += strerror ( errno );
00272     throw PumaException ( PumaException::intolerable, msg );
00273   }
00274   rewind ( filePointer );
00275   if ( ftell ( filePointer ) != 0 )
00276   {
00277     string msg ( "can't peek into file start, rewind failed: " );
00278     msg += strerror ( errno );
00279     throw PumaException ( PumaException::intolerable, msg );
00280   }
00281 
00282 #ifdef HAVE_LIBPNG_ANDISIMPLEMENTED
00283   if ( png_sig_cmp ( magicChars, 0, lookAheadLength ) == 0 )
00284   {
00285     success = readImageColorPNG ( img, filePointer );
00286   }
00287   else
00288 #endif
00289 #ifdef HAVE_LIBJPEG_ANDISIMPLEMENTED
00290     if ( ( magicChars[0] == 0xff ) && ( magicChars[1] == 0xd8 ) )
00291     {
00292       success = readImageColorJPEGFromFile ( img, filePointer );
00293     }
00294     else
00295 #endif
00296 #ifdef USE_BUILTIN_PNM_ANDISIMPLEMENTED
00297       if ( ( magicChars[0] == 'P' )
00298            && ( ( magicChars[1] >= '1' ) && ( magicChars[1] <= '6' ) )
00299            && ( ( magicChars[2] == ' ' ) || ( magicChars[2] == '\n' ) || ( magicChars[2] == '\r' ) || ( magicChars[2] == '\t' ) )
00300          )
00301       {
00302         success = readImageColorBuiltinPNM ( img, filePointer );
00303       }
00304 #endif
00305   fclose ( filePointer );
00306 
00307 #ifdef HAVE_IMAGEMAGICK
00308   if ( ! success ) // ImageMagick++ has no method to read from a file pointer :-(
00309   {
00310     success = readImageColorMagick ( img, filename );
00311   }
00312 #endif
00313   if ( ! success )
00314   {
00315     string msg ( "unknown image format, can't read file '" );
00316     msg += filename + "'.";
00317     throw PumaException ( PumaException::intolerable, msg );
00318     success = false;
00319   }
00320   return success;
00321 }
00322 
00323 // --------------------------------------------------------
00324 // reader for PNM files
00325 // --------------------------------------------------------
00326 
00336 static void skipPNMcomment ( FILE *fp )
00337 {
00338   int c = getc ( fp );
00339   while ( c != '\n' && c != EOF )
00340   {
00341     c = getc ( fp );
00342   }
00343 }
00344 
00355 static int getPNMinteger ( FILE *fp )
00356 {
00357   int ch = ' ';
00358 
00359   while ( 1 ) /* eat comments and white space */
00360   {
00361     if ( ch == '#' ) /* if we're at a comment, read to end of line */
00362       skipPNMcomment ( fp );
00363     if ( ch == EOF ) return 0;
00364     if ( ch >= '0' && ch <= '9' ) break; /* found a digit */
00365     ch = getc ( fp );
00366   }
00367 
00368   /* we're at the start of a number, continue until we hit a non-digit */
00369   int value = 0;
00370   while ( 1 )
00371   {
00372     value = ( value * 10 ) + ( ch - '0' );
00373     ch = getc ( fp );
00374     if ( ch == EOF ) return value;
00375     if ( ch < '0' || ch > '9' ) break;
00376   }
00377   return value;
00378 }
00379 
00380 
00381 static bool readPNMheader ( FILE *filePointer, int &pCode, int &pWid, int &pHig, int &pDep )
00382 {
00383   int ch;
00384 
00385   ch = getc ( filePointer );
00386   if ( ch != 'P' )
00387   {
00388     // TODO PumaMessage ( msgImportant, "file is not a PNM file" );
00389     return false;
00390   }
00391   pCode = getc ( filePointer ) - '0';
00392   if ( ( pCode < 1 ) || ( pCode > 6 ) )
00393   {
00394     // TODO  PumaMessage ( msgImportant, "file is not a classic PNM file" );
00395     return false;
00396   }
00397   pWid  = getPNMinteger ( filePointer );
00398   pHig = getPNMinteger ( filePointer );
00399   if ( ( pWid < 1 ) || ( pHig < 1 ) )
00400   {
00401     // TODO PumaMessage ( msgImportant, "file is not a valid PNM file (width or height < 1)" );
00402     return false;
00403   }
00404   if ( ( pCode == 1 ) || ( pCode == 4 ) )
00405   {
00406     pDep = 1;
00407   }
00408   else
00409   {
00410     pDep = getPNMinteger ( filePointer );
00411     if ( pDep > 255 )
00412     {
00413       // TODO PumaMessage ( msgNotice, "reading PNM files with depth > 255 not yet supported by builtin" );
00414       return false;
00415     }
00416   }
00417   return true;
00418 }
00419 
00420 static bool readImageGrayBuiltinPNM ( GrayLevelImage8 &img,
00421                                       FILE *filePointer )
00422 {
00423   int pnmCode;
00424   int pnmWidth, pnmHeight, pnmDepth;
00425 
00426   if ( ! readPNMheader ( filePointer, pnmCode, pnmWidth, pnmHeight, pnmDepth ) )
00427     return false;
00428 
00429   img.resize ( pnmWidth, pnmHeight );
00430   int bytesRead = 0;
00431   switch ( pnmCode )
00432   {
00433       // =============================================================================
00434     case 1:   // PBM in ASCII, depth is 1 by definition, 1 is black, 0 is white
00435     {
00436       // TODO PumaMessage ( msgNotice, "builtin reading PBM (P1) files not yet implemented" );
00437       return false; // let ImageMagick try it
00438       break;
00439     }
00440     // =============================================================================
00441     case 2:   // PGM in ASCII, depth from file, 0 is black, depth is white
00442     {
00443       // TODO PumaMessage ( msgNotice, "builtin reading PGM (P2) files not yet implemented" );
00444       return false; // let ImageMagick try it
00445       break;
00446     }
00447     // =============================================================================
00448     case 3:   // PPM in ASCII, depth from file, 0 is black, depth is white
00449     {
00450       // TODO PumaMessage ( msgNotice, "builtin reading PPM (P3) files not yet implemented" );
00451       return false; // let ImageMagick try it
00452       break;
00453     }
00454     // =============================================================================
00455     case 4:   // PBM binary, depth is 1 by definition, 1 is black, 0 is white
00456     {
00457       // TODO PumaMessage ( msgNotice, "builtin reading PBM (P4) files not yet implemented" );
00458       return false; // let ImageMagick try it
00459       break;
00460     }
00461     // =============================================================================
00462     case 5:   // PGM binary, depth from file, 0 is black, depth is white
00463     {
00464       img.setValueRangeMaximum ( pnmDepth );
00465       GrayLevelImage8::ElementType **ptr = img.unsafeRowPointerArray();
00466       for ( int y = 0; y < pnmHeight; y++ )
00467       {
00468         bytesRead += fread ( ptr[y], 1, pnmWidth * img.numberOfChannels(), filePointer );
00469       }
00470       if ( bytesRead != pnmWidth * pnmHeight * img.numberOfChannels() )
00471       {
00472         string msg ( "File appears to be truncated: " );
00473         // msg += strerror(errno); "(got %d - expected %d bytes)\n", bytesRead, xs*ys);
00474         throw PumaException ( PumaException::intolerable, msg );
00475       }
00476       break;
00477     }
00478     // =============================================================================
00479     case 6:   // PPM binary, depth from file, RGB, 0 is black, depth is white
00480     {
00481       img.setValueRangeMaximum ( pnmDepth );
00482       // TODO PumaMessage ( msgNotice, "reading PPM image into GrayLevelImage, discarding color" );
00483       for ( int y = 0; y < pnmHeight; y++ )
00484       {
00485         for ( int x = 0; x < pnmWidth; x++ )
00486         {
00487           int val = 299 * getc ( filePointer );
00488           val += 587 * getc ( filePointer );
00489           val += 114 * getc ( filePointer );
00490           img.sample ( x, y, 0 ) = byte ( val / 1000 );
00491           bytesRead += 3;
00492         }
00493       }
00494       if ( bytesRead != pnmWidth * pnmHeight * 3 )
00495       {
00496         string msg ( "File appears to be truncated: " );
00497         // msg += strerror(errno); "(got %d - expected %d bytes)\n", bytesRead, xs*ys);
00498         throw PumaException ( PumaException::intolerable, msg );
00499       }
00500       break;
00501     }
00502     // =============================================================================
00503     case 7:   // PAM, totally different, yet more flexible format of NetPBM
00504     {
00505       // TODO PumaMessage ( msgNotice, "builtin PNM reader can't handle PNM:PAM files" );
00506       return false; // let ImageMagick try it
00507       break;
00508     }
00509     // =============================================================================
00510     default:   // unknown
00511     {
00512       // TODO PumaMessage ( msgNotice, "builtin PNM reader: unknown PNM format" );
00513       return false; // let ImageMagick try it
00514       break;
00515     }
00516   }
00517   return true;
00518 }
00519 
00520 static bool readImageColorBuiltinPNM ( ColorImageRGB8 &img,
00521                                        FILE *filePointer )
00522 {
00523   int pnmCode;
00524   int pnmWidth, pnmHeight, pnmDepth;
00525 
00526   if ( ! readPNMheader ( filePointer, pnmCode, pnmWidth, pnmHeight, pnmDepth ) )
00527     return false;
00528 
00529   img.resize ( pnmWidth, pnmHeight );
00530   int bytesRead = 0;
00531   switch ( pnmCode )
00532   {
00533       // =============================================================================
00534     case 1:   // PBM in ASCII, depth is 1 by definition, 1 is black, 0 is white
00535     {
00536       // TODO PumaMessage ( msgNotice, "builtin reading PBM (P1) files not yet implemented" );
00537       return false; // let ImageMagick try it
00538       break;
00539     }
00540     // =============================================================================
00541     case 2:   // PGM in ASCII, depth from file, 0 is black, depth is white
00542     {
00543       // TODO PumaMessage ( msgNotice, "builtin reading PGM (P2) files not yet implemented" );
00544       return false; // let ImageMagick try it
00545       break;
00546     }
00547     // =============================================================================
00548     case 3:   // PPM in ASCII, depth from file, 0 is black, depth is white
00549     {
00550       // TODO PumaMessage ( msgNotice, "builtin reading PPM (P3) files not yet implemented" );
00551       return false; // let ImageMagick try it
00552       break;
00553     }
00554     // =============================================================================
00555     case 4:   // PBM binary, depth is 1 by definition, 1 is black, 0 is white
00556     {
00557       // TODO PumaMessage ( msgNotice, "builtin reading PBM (P4) files not yet implemented" );
00558       return false; // let ImageMagick try it
00559       break;
00560     }
00561     // =============================================================================
00562     case 5:   // PGM binary, depth from file, 0 is black, depth is white
00563     {
00564       img.setValueRangeMaximum ( pnmDepth );
00565       ColorImageRGB8::PixelType **ptr = img.unsafeRowPointerArray();
00566       byte *readBuf = new byte[pnmWidth];
00567       for ( int y = 0; y < pnmHeight; y++ )
00568       {
00569         ColorImageRGB8::ElementType *sptr = & ( ptr[y][0][0] );
00570         fread ( readBuf, pnmWidth, 1, filePointer );
00571         byte * valp = readBuf;
00572         for ( int x = 0; x < pnmWidth; x++ )
00573         {
00574           *sptr++ = *valp;
00575           *sptr++ = *valp;
00576           *sptr++ = *valp++;
00577           bytesRead += 1;
00578         }
00579       }
00580       delete readBuf;
00581       if ( bytesRead != pnmWidth * pnmHeight * 1 )
00582       {
00583         string msg ( "File appears to be truncated: " );
00584         // msg += strerror(errno); "(got %d - expected %d bytes)\n", bytesRead, xs*ys);
00585         throw PumaException ( PumaException::intolerable, msg );
00586       }
00587       break;
00588     }
00589     // =============================================================================
00590     case 6:   // PPM binary, depth from file, RGB, 0 is black, depth is white
00591     {
00592       img.setValueRangeMaximum ( pnmDepth );
00593       ColorImageRGB8::PixelType **ptr = img.unsafeRowPointerArray();
00594       for ( int y = 0; y < pnmHeight; y++ )
00595       {
00596         bytesRead += fread ( ptr[y], 1, pnmWidth * img.numberOfChannels(), filePointer );
00597       }
00598       if ( bytesRead != pnmWidth * pnmHeight * img.numberOfChannels() )
00599       {
00600         string msg ( "File appears to be truncated: " );
00601         // msg += strerror(errno); "(got %d - expected %d bytes)\n", bytesRead, xs*ys);
00602         throw PumaException ( PumaException::intolerable, msg );
00603       }
00604       break;
00605     }
00606     // =======================================================================
00607     case 7:   // PAM, totally different, yet more flexible format of NetPBM
00608     {
00609       // TODO PumaMessage ( msgNotice, "builtin PNM reader can't handle PNM:PAM files" );
00610       return false; // let ImageMagick try it
00611       break;
00612     }
00613     // =======================================================================
00614     default:   // unknown
00615     {
00616       // TODO PumaMessage ( msgNotice, "builtin PNM reader: unknown PNM format" );
00617       return false; // let ImageMagick try it
00618       break;
00619     }
00620   }
00621   return true;
00622 }
00623 
00624 
00625 // --------------------------------------------------------
00626 // specific reader for PNG files (using libpng from www.libpng.org)
00627 // --------------------------------------------------------
00628 
00629 #ifdef HAVE_LIBJPEG
00630 
00631 #if BITS_IN_JSAMPLE != 8
00632 # error "can't yet deal with JPEG samples other than 8 Bit"
00633 #endif
00634 
00635 static bool readImageGrayJPEG ( GrayLevelImage8 &img, FILE *filePointer )
00636 {
00637   struct jpeg_decompress_struct cinfo;
00638   struct jpeg_error_mgr jerr;
00639 
00640   rewind ( filePointer );
00641   cinfo.err = jpeg_std_error ( &jerr );
00642   jpeg_create_decompress ( &cinfo );
00643   jpeg_stdio_src ( &cinfo, filePointer );
00644   int ret = jpeg_read_header ( &cinfo, TRUE );
00645   if ( ret != JPEG_HEADER_OK )
00646   {
00647     string msg ( "can't read JPEG header." );
00648     throw PumaException ( PumaException::intolerable, msg );
00649     return false;
00650   }
00651 
00652 #if JPEG_LIB_VERSION <= 62
00653   // jpeglib v.6b will fail on these color spaces and raise an exception
00654   // when calling jpeg_start_decompress(). So let's check before ...
00655   // Apparently there is no implicit/automatic conversion CMYK -> RGB
00656   if ( ( cinfo.jpeg_color_space == JCS_CMYK )
00657        || ( cinfo.jpeg_color_space == JCS_YCCK ) )
00658   {
00659     string msg ( "can't read JPEG files with CMYC or YCCK color space natively." );
00660     throw PumaException ( PumaException::intolerable, msg );
00661     return false;
00662   }
00663 #endif
00664 
00665   // set non-default decompression parameters here: force gray scale
00666   if ( cinfo.output_components != 1 )
00667     // TODO PumaMessage ( msgNotice, "reading JPEG image into GrayLevelImage, "
00668 //"discarding color" );
00669   cinfo.out_color_space = JCS_GRAYSCALE;
00670   cinfo.out_color_components = 1;
00671   cinfo.output_components = 1;
00672 
00673   int wid = cinfo.image_width;
00674   int hig = cinfo.image_height;
00675 
00676   jpeg_start_decompress ( &cinfo );
00677 
00678   img.resize ( wid, hig );
00679   // byte ** row_ptrs = img;
00680   byte ** row_ptrs = img.unsafeRowPointerArray();
00681   while ( cinfo.output_scanline < cinfo.output_height )
00682   {
00683     jpeg_read_scanlines ( &cinfo, &row_ptrs[cinfo.output_scanline],
00684                           cinfo.output_height - cinfo.output_scanline );
00685   }
00686 
00687   jpeg_finish_decompress ( &cinfo );
00688   jpeg_destroy_decompress ( &cinfo );
00689   return true;
00690 }
00691 
00692 static bool readImageColorJPEGFromFile ( ColorImageRGB8 &img, FILE *filePointer )
00693 {
00694   struct jpeg_decompress_struct cinfo;
00695   struct jpeg_error_mgr jerr;
00696 
00697   rewind ( filePointer );
00698   cinfo.err = jpeg_std_error ( &jerr );
00699   jpeg_create_decompress ( &cinfo );
00700   jpeg_stdio_src ( &cinfo, filePointer );
00701 
00702   return readImageColorJPEG_generic ( img, cinfo );
00703 }
00704 
00705 static bool readImageColorJPEGFromMemory ( ColorImageRGB8 &img, JOCTET * ptr, size_t numBytes )
00706 {
00707   struct jpeg_decompress_struct cinfo;
00708   struct jpeg_error_mgr jerr;
00709 
00710   cinfo.err = jpeg_std_error ( &jerr );
00711   jpeg_create_decompress ( &cinfo );
00712   jpeg_memory_src ( &cinfo, ptr, numBytes );
00713 
00714   return readImageColorJPEG_generic ( img, cinfo );
00715 }
00716 
00717 static bool readImageColorJPEG_generic ( ColorImageRGB8 &img, struct jpeg_decompress_struct &cinfo )
00718 {
00719   int ret = jpeg_read_header ( &cinfo, TRUE );
00720   if ( ret != JPEG_HEADER_OK )
00721   {
00722     string msg ( "can't read JPEG header." );
00723     throw PumaException ( PumaException::intolerable, msg );
00724     return false;
00725   }
00726 
00727 #if JPEG_LIB_VERSION <= 62
00728   // jpeglib v.6b will fail on these color spaces and raise an exception
00729   // when calling jpeg_start_decompress(). So let's check before ...
00730   // Apparently there is no implicit/automatic conversion CMYK -> RGB
00731   if ( ( cinfo.jpeg_color_space == JCS_CMYK )
00732        || ( cinfo.jpeg_color_space == JCS_YCCK ) )
00733   {
00734     string msg ( "can't read JPEG files with CMYC or YCCK color space natively." );
00735     throw PumaException ( PumaException::intolerable, msg );
00736     return false;
00737   }
00738 #endif
00739 
00740   // set non-default decompression parameters here: force gray scale
00741   if ( cinfo.output_components == 1 )
00742     // TODO PumaMessage ( msgNotice, "expanding graylevel JPEG image to RGB8 color image" );
00743   cinfo.out_color_space = JCS_RGB;
00744   cinfo.out_color_components = 3;
00745   cinfo.output_components = 3;
00746 
00747   int wid = cinfo.image_width;
00748   int hig = cinfo.image_height;
00749 
00750   jpeg_start_decompress ( &cinfo );
00751 
00752   img.resize ( wid, hig );
00753   // byte ** row_ptrs = img;
00754   byte ** row_ptrs = ( JSAMPLE ** ) img.unsafeRowPointerArray();
00755   while ( cinfo.output_scanline < cinfo.output_height )
00756   {
00757     jpeg_read_scanlines ( &cinfo, &row_ptrs[cinfo.output_scanline],
00758                           cinfo.output_height - cinfo.output_scanline );
00759   }
00760 
00761   jpeg_finish_decompress ( &cinfo );
00762   jpeg_destroy_decompress ( &cinfo );
00763   return true;
00764 }
00765 #endif  /* HAVE_LIBJPEG */
00766 
00767 // --------------------------------------------------------
00768 // specific reader for JPEG files (using libjpeg from www.ijg.org)
00769 // --------------------------------------------------------
00770 
00771 #ifdef HAVE_LIBPNG
00772 
00773 static bool readImageGrayPNG ( GrayLevelImage8 &img, FILE *filePointer )
00774 {
00775   enum { cs_gray, cs_rgb, cs_rgba } outColorSpace = cs_gray;
00776   enum { st_8bit, st_16bit, st_other } outSampleType = st_8bit;
00777 
00778   png_structp png_ptr = png_create_read_struct
00779                         ( PNG_LIBPNG_VER_STRING, ( png_voidp ) NULL,
00780                           NULL, NULL );
00781   if ( !png_ptr )
00782   {
00783     string msg ( "can't read PNG header." );
00784     throw PumaException ( PumaException::intolerable, msg );
00785     return false;
00786   }
00787 
00788   png_infop info_ptr = png_create_info_struct ( png_ptr );
00789   if ( !info_ptr )
00790   {
00791     png_destroy_read_struct ( &png_ptr,
00792                               ( png_infopp ) NULL, ( png_infopp ) NULL );
00793     string msg ( "error setting up PNG structures." );
00794     throw PumaException ( PumaException::intolerable, msg );
00795     return false;
00796   }
00797 
00798   png_infop end_info = png_create_info_struct ( png_ptr );
00799   if ( !end_info )
00800   {
00801     png_destroy_read_struct ( &png_ptr, &info_ptr,
00802                               ( png_infopp ) NULL );
00803     string msg ( "error setting up PNG end structures." );
00804     throw PumaException ( PumaException::intolerable, msg );
00805     return false;
00806   }
00807 
00808   if ( setjmp ( png_jmpbuf ( png_ptr ) ) )
00809   {
00810     png_destroy_read_struct ( &png_ptr, &info_ptr,
00811                               &end_info );
00812     string msg ( "severe error reading PNG file." );
00813     throw PumaException ( PumaException::intolerable, msg );
00814     return false;
00815   }
00816 
00817   rewind ( filePointer );
00818   png_init_io ( png_ptr, filePointer );
00819   png_read_info ( png_ptr, info_ptr );
00820 
00821   int wid = png_get_image_width ( png_ptr, info_ptr );
00822   int hig = png_get_image_height ( png_ptr, info_ptr );
00823   int color_type = png_get_color_type ( png_ptr, info_ptr );
00824   int bit_depth = png_get_bit_depth ( png_ptr, info_ptr );
00825   img.resize ( wid, hig );
00826 
00827   if ( color_type == PNG_COLOR_TYPE_PALETTE )
00828     png_set_palette_to_rgb ( png_ptr );
00829 
00830   if ( color_type == PNG_COLOR_TYPE_GRAY
00831        && bit_depth < 8 )
00832     png_set_expand_gray_1_2_4_to_8 ( png_ptr );
00833 
00834   if ( ( outSampleType == st_8bit ) && ( bit_depth == 16 ) )
00835     png_set_strip_16 ( png_ptr );
00836 
00837   if ( ( outColorSpace != cs_rgba ) && ( color_type & PNG_COLOR_MASK_ALPHA ) )
00838     png_set_strip_alpha ( png_ptr );
00839 
00840   if ( bit_depth < 8 )
00841     png_set_packing ( png_ptr );
00842 
00843   if ( ( outColorSpace == cs_gray )
00844        && ( color_type == PNG_COLOR_TYPE_RGB ||
00845             color_type == PNG_COLOR_TYPE_RGB_ALPHA ) )
00846   {
00847     // must use error_action == 2, since =1 may cause abort due to bug in libpng 1.2.18
00848     png_set_rgb_to_gray_fixed ( png_ptr, 2, 29900, 58700 );
00849   }
00850 
00851   // int number_of_passes = png_set_interlace_handling(png_ptr);
00852   png_read_update_info ( png_ptr, info_ptr );
00853 
00854   // byte ** row_ptrs = img;
00855   byte ** row_ptrs = img.unsafeRowPointerArray();
00856   png_read_image ( png_ptr, row_ptrs );
00857 
00858   png_read_end ( png_ptr, end_info );
00859   png_destroy_read_struct ( &png_ptr, &info_ptr, &end_info );
00860   return true;
00861 }
00862 
00863 static bool readImageColorPNG ( ColorImageRGB8 &img, FILE *filePointer )
00864 {
00865   enum { cs_gray, cs_rgb, cs_rgba } outColorSpace = cs_rgb;
00866   enum { st_8bit, st_16bit, st_other } outSampleType = st_8bit;
00867 
00868   png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
00869 
00870   if ( !png_ptr )
00871   {
00872     string msg ( "can't read PNG header." );
00873     throw PumaException ( PumaException::intolerable, msg );
00874     return false;
00875   }
00876 
00877   png_infop info_ptr = png_create_info_struct ( png_ptr );
00878   if ( !info_ptr )
00879   {
00880     png_destroy_read_struct ( &png_ptr,
00881                               ( png_infopp ) NULL, ( png_infopp ) NULL );
00882     string msg ( "error setting up PNG structures." );
00883     throw PumaException ( PumaException::intolerable, msg );
00884     return false;
00885   }
00886 
00887   png_infop end_info = png_create_info_struct ( png_ptr );
00888   if ( !end_info )
00889   {
00890     png_destroy_read_struct ( &png_ptr, &info_ptr,
00891                               ( png_infopp ) NULL );
00892     string msg ( "error setting up PNG end structures." );
00893     throw PumaException ( PumaException::intolerable, msg );
00894     return false;
00895   }
00896 
00897   if ( setjmp ( png_jmpbuf ( png_ptr ) ) )
00898   {
00899     png_destroy_read_struct ( &png_ptr, &info_ptr,
00900                               &end_info );
00901     string msg ( "severe error reading PNG file." );
00902     throw PumaException ( PumaException::intolerable, msg );
00903     return false;
00904   }
00905 
00906   rewind ( filePointer );
00907   png_init_io ( png_ptr, filePointer );
00908   png_read_info ( png_ptr, info_ptr );
00909 
00910   int wid = png_get_image_width ( png_ptr, info_ptr );
00911   int hig = png_get_image_height ( png_ptr, info_ptr );
00912   int color_type = png_get_color_type ( png_ptr, info_ptr );
00913   int bit_depth = png_get_bit_depth ( png_ptr, info_ptr );
00914   img.resize ( wid, hig );
00915 
00916   if ( color_type == PNG_COLOR_TYPE_PALETTE )
00917     png_set_palette_to_rgb ( png_ptr );
00918 
00919   if ( color_type == PNG_COLOR_TYPE_GRAY
00920        && bit_depth < 8 )
00921     png_set_expand_gray_1_2_4_to_8 ( png_ptr );
00922 
00923   if ( ( outSampleType == st_8bit ) && ( bit_depth == 16 ) )
00924     png_set_strip_16 ( png_ptr );
00925 
00926   if ( ( outColorSpace != cs_rgba ) && ( color_type & PNG_COLOR_MASK_ALPHA ) )
00927     png_set_strip_alpha ( png_ptr );
00928 
00929   if ( bit_depth < 8 )
00930     png_set_packing ( png_ptr );
00931 
00932   if ( ( outColorSpace == cs_gray )
00933        && ( color_type == PNG_COLOR_TYPE_RGB ||
00934             color_type == PNG_COLOR_TYPE_RGB_ALPHA ) )
00935     png_set_rgb_to_gray_fixed ( png_ptr, 1, 29900, 58700 );
00936 
00937   if ( ( outColorSpace == cs_rgb )
00938        && ( color_type == PNG_COLOR_TYPE_GRAY ||
00939             color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) )
00940     png_set_gray_to_rgb ( png_ptr );
00941 
00942   // int number_of_passes = png_set_interlace_handling(png_ptr);
00943   png_read_update_info ( png_ptr, info_ptr );
00944 
00945   // byte ** row_ptrs = img;
00946   byte ** row_ptrs = ( byte** ) ( img.unsafeRowPointerArray() );
00947   png_read_image ( png_ptr, row_ptrs );
00948 
00949   png_read_end ( png_ptr, end_info );
00950   png_destroy_read_struct ( &png_ptr, &info_ptr, &end_info );
00951   return true;
00952 }
00953 
00954 #endif  /* HAVE_LIBPNG */
00955 
00956 
00957 // --------------------------------------------------------
00958 // reader for other image files (using libMagick++ from www.imagemagick.org)
00959 // --------------------------------------------------------
00960 
00961 #ifdef HAVE_IMAGEMAGICK
00962 
00963 static bool readImageGrayMagick ( GrayLevelImage8 &img, string filename )
00964 {
00965   Magick::Image magickImage;
00966 
00967   try
00968   {
00969     magickImage.read ( filename );
00970   }
00971 //   catch( Magick::Warning &warning_ ) {
00972 //     cout << "Caught Image Magic Warning: " << warning_.what() << endl;
00973 //   }
00974   catch ( Magick::Exception &error_ )
00975   {
00976     string msg ( "Caught Image Magic Exception: " );
00977     msg += error_.what();
00978     throw PumaException ( PumaException::intolerable, msg );
00979   }
00980 
00981   unsigned int wid = magickImage.columns();
00982   unsigned int hig = magickImage.rows();
00983   double scaleQuotient = 1.0 / 255.0;
00984 
00985   img.resize ( wid, hig );
00986   if ( magickImage.type() != Magick::GrayscaleType ) // found a color image
00987   {
00988     scaleQuotient *= 1000; // 299 + 587 + 114 == 1000
00989     PumaMessage ( msgNotice, "reading Magick color image into GrayLevelImage, discarding color" );
00990     for ( unsigned int y = 0; y < hig; y++ )
00991       for ( unsigned int x = 0; x < wid; x++ )
00992       {
00993         Magick::ColorRGB col = magickImage.pixelColor ( x, y );
00994         double val = 299 * col.red()
00995                      + 587 * col.green()
00996                      + 114 * col.blue();
00997         img.sample ( x, y, 0 ) = GrayLevelImage8::ElementType ( val / scaleQuotient );
00998       }
00999   }
01000   else   // found a gray-level image
01001   {
01002     for ( unsigned int y = 0; y < hig; y++ )
01003       for ( unsigned int x = 0; x < wid; x++ )
01004       {
01005         Magick::ColorRGB col = magickImage.pixelColor ( x, y );
01006         img.sample ( x, y, 0 ) = GrayLevelImage8::ElementType ( col.red() / scaleQuotient );
01007       }
01008   }
01009 
01010   return true;
01011 }
01012 
01013 static bool readImageGrayMagick ( GrayLevelImage16 &img, string filename )
01014 {
01015   Magick::Image magickImage;
01016 
01017   try
01018   {
01019     magickImage.read ( filename );
01020   }
01021 //   catch( Magick::Warning &warning_ ) {
01022 //     cout << "Caught Image Magic Warning: " << warning_.what() << endl;
01023 //   }
01024   catch ( Magick::Exception &error_ )
01025   {
01026     string msg ( "Caught Image Magic Exception: " );
01027     msg += error_.what();
01028     throw PumaException ( PumaException::intolerable, msg );
01029   }
01030 
01031   unsigned int wid = magickImage.columns();
01032   unsigned int hig = magickImage.rows();
01033   double scaleQuotient = 1.0 / 65535.0;
01034 
01035   img.resize ( wid, hig );
01036   if ( magickImage.type() != Magick::GrayscaleType ) // found a color image
01037   {
01038     scaleQuotient *= 1000; // 299 + 587 + 114 == 1000
01039     PumaMessage ( msgNotice, "reading Magick color image into GrayLevelImage, discarding color" );
01040     for ( unsigned int y = 0; y < hig; y++ )
01041       for ( unsigned int x = 0; x < wid; x++ )
01042       {
01043         Magick::ColorRGB col = magickImage.pixelColor ( x, y );
01044         double val = 299 * col.red()
01045                      + 587 * col.green()
01046                      + 114 * col.blue();
01047         img.sample ( x, y, 0 ) = GrayLevelImage8::ElementType ( val / scaleQuotient );
01048       }
01049   }
01050   else   // found a gray-level image
01051   {
01052     for ( unsigned int y = 0; y < hig; y++ )
01053       for ( unsigned int x = 0; x < wid; x++ )
01054       {
01055         Magick::ColorRGB col = magickImage.pixelColor ( x, y );
01056         img.sample ( x, y, 0 ) = GrayLevelImage16::ElementType ( col.red() / scaleQuotient );
01057       }
01058   }
01059 
01060   return true;
01061 }
01062 
01063 static bool readImageColorMagick ( ColorImageRGB8 &img, string filename )
01064 {
01065   Magick::Image magickImage;
01066 
01067   try
01068   {
01069     magickImage.read ( filename );
01070   }
01071 //   catch( Magick::Warning &warning_ ) {
01072 //     cout << "Caught Image Magic Warning: " << warning_.what() << endl;
01073 //   }
01074   catch ( Magick::Exception &error_ )
01075   {
01076     string msg ( "Caught Image Magic Exception: " );
01077     msg += error_.what();
01078     throw PumaException ( PumaException::intolerable, msg );
01079   }
01080 
01081   unsigned int wid = magickImage.columns();
01082   unsigned int hig = magickImage.rows();
01083   long scaleQuotient = 1;
01084   if ( magickImage.depth() == 16 )
01085     scaleQuotient = 257; // yes, really 257, to map 65535 -> 255 !!
01086 
01087   img.resize ( wid, hig );
01088   if ( magickImage.type() != Magick::GrayscaleType ) // found a color image
01089   {
01090     for ( unsigned int y = 0; y < hig; y++ )
01091       for ( unsigned int x = 0; x < wid; x++ )
01092       {
01093         Magick::Color col = magickImage.pixelColor ( x, y );
01094         img.sample ( x, y, 0 ) = ColorImageRGB8::ElementType ( col.redQuantum() / scaleQuotient );
01095         img.sample ( x, y, 1 ) = ColorImageRGB8::ElementType ( col.greenQuantum() / scaleQuotient );
01096         img.sample ( x, y, 2 ) = ColorImageRGB8::ElementType ( col.blueQuantum() / scaleQuotient );
01097       }
01098   }
01099   else   // found a gray-level image
01100   {
01101     for ( unsigned int y = 0; y < hig; y++ )
01102       for ( unsigned int x = 0; x < wid; x++ )
01103       {
01104         Magick::Color col = magickImage.pixelColor ( x, y );
01105         img.sample ( x, y, 0 ) =
01106           img.sample ( x, y, 1 ) =
01107             img.sample ( x, y, 2 ) =
01108               ColorImageRGB8::ElementType ( col.redQuantum() / scaleQuotient );
01109       }
01110   }
01111 
01112   return true;
01113 }
01114 
01115 static bool readImageColorMagick ( ColorImageRGBa8 &img, string filename )
01116 {
01117   Magick::Image magickImage;
01118 
01119   try
01120   {
01121     magickImage.read ( filename );
01122   }
01123 //   catch( Magick::Warning &warning_ ) {
01124 //     cout << "Caught Image Magic Warning: " << warning_.what() << endl;
01125 //   }
01126   catch ( Magick::Exception &error_ )
01127   {
01128     string msg ( "Caught Image Magic Exception: " );
01129     msg += error_.what();
01130     throw PumaException ( PumaException::intolerable, msg );
01131   }
01132 
01133   unsigned int wid = magickImage.columns();
01134   unsigned int hig = magickImage.rows();
01135   bool hasAlpha = magickImage.matte();
01136   const byte fullyOpaque = byte ( img.getValueRangeMaximum() );
01137   long scaleQuotient = 1;
01138   if ( magickImage.depth() == 16 )
01139     scaleQuotient = 257; // yes, really 257, to map 65535 -> 255 !!
01140 
01141   img.resize ( wid, hig );
01142   if ( magickImage.type() != Magick::GrayscaleType ) // found a color image
01143   {
01144     for ( unsigned int y = 0; y < hig; y++ )
01145       for ( unsigned int x = 0; x < wid; x++ )
01146       {
01147         Magick::Color col = magickImage.pixelColor ( x, y );
01148         RGBa8 &pixel = img.sample ( x, y, 0 );
01149         pixel.r = ColorImageRGB8::ElementType ( col.redQuantum() / scaleQuotient );
01150         pixel.g = ColorImageRGB8::ElementType ( col.greenQuantum() / scaleQuotient );
01151         pixel.b = ColorImageRGB8::ElementType ( col.blueQuantum() / scaleQuotient );
01152         pixel.a = ( hasAlpha )
01153                   ? ColorImageRGB8::ElementType ( col.alphaQuantum() / scaleQuotient )
01154                   : fullyOpaque ;
01155       }
01156   }
01157   else   // found a gray-level image
01158   {
01159     Magick::Color col;
01160     byte val;
01161     for ( unsigned int y = 0; y < hig; y++ )
01162       for ( unsigned int x = 0; x < wid; x++ )
01163       {
01164         col = magickImage.pixelColor ( x, y );
01165         val = col.redQuantum() / scaleQuotient;
01166         img.sample ( x, y, 0 ) = val;
01167         img.sample ( x, y, 1 ) = val;
01168         img.sample ( x, y, 2 ) = val;
01169         img.sample ( x, y, 3 ) = ( hasAlpha )
01170                                  ? ColorImageRGB8::ElementType ( col.alphaQuantum() / scaleQuotient )
01171                                  : fullyOpaque ;
01172       }
01173   }
01174 
01175   return true;
01176 }
01177 #endif  /* HAVE_IMAGEMAGICK */


obj_rec_gui
Author(s): AGAS/agas@uni-koblenz.de
autogenerated on Mon Oct 6 2014 02:53:43