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
00021
00022 # include <jpeglib.h>
00023
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
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" );
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 )
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" );
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 )
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" );
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 )
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" );
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 )
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
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 )
00360 {
00361 if ( ch == '#' )
00362 skipPNMcomment ( fp );
00363 if ( ch == EOF ) return 0;
00364 if ( ch >= '0' && ch <= '9' ) break;
00365 ch = getc ( fp );
00366 }
00367
00368
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
00389 return false;
00390 }
00391 pCode = getc ( filePointer ) - '0';
00392 if ( ( pCode < 1 ) || ( pCode > 6 ) )
00393 {
00394
00395 return false;
00396 }
00397 pWid = getPNMinteger ( filePointer );
00398 pHig = getPNMinteger ( filePointer );
00399 if ( ( pWid < 1 ) || ( pHig < 1 ) )
00400 {
00401
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
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:
00435 {
00436
00437 return false;
00438 break;
00439 }
00440
00441 case 2:
00442 {
00443
00444 return false;
00445 break;
00446 }
00447
00448 case 3:
00449 {
00450
00451 return false;
00452 break;
00453 }
00454
00455 case 4:
00456 {
00457
00458 return false;
00459 break;
00460 }
00461
00462 case 5:
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
00474 throw PumaException ( PumaException::intolerable, msg );
00475 }
00476 break;
00477 }
00478
00479 case 6:
00480 {
00481 img.setValueRangeMaximum ( pnmDepth );
00482
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
00498 throw PumaException ( PumaException::intolerable, msg );
00499 }
00500 break;
00501 }
00502
00503 case 7:
00504 {
00505
00506 return false;
00507 break;
00508 }
00509
00510 default:
00511 {
00512
00513 return false;
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:
00535 {
00536
00537 return false;
00538 break;
00539 }
00540
00541 case 2:
00542 {
00543
00544 return false;
00545 break;
00546 }
00547
00548 case 3:
00549 {
00550
00551 return false;
00552 break;
00553 }
00554
00555 case 4:
00556 {
00557
00558 return false;
00559 break;
00560 }
00561
00562 case 5:
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
00585 throw PumaException ( PumaException::intolerable, msg );
00586 }
00587 break;
00588 }
00589
00590 case 6:
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
00602 throw PumaException ( PumaException::intolerable, msg );
00603 }
00604 break;
00605 }
00606
00607 case 7:
00608 {
00609
00610 return false;
00611 break;
00612 }
00613
00614 default:
00615 {
00616
00617 return false;
00618 break;
00619 }
00620 }
00621 return true;
00622 }
00623
00624
00625
00626
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
00654
00655
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
00666 if ( cinfo.output_components != 1 )
00667
00668
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
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
00729
00730
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
00741 if ( cinfo.output_components == 1 )
00742
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
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
00766
00767
00768
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
00848 png_set_rgb_to_gray_fixed ( png_ptr, 2, 29900, 58700 );
00849 }
00850
00851
00852 png_read_update_info ( png_ptr, info_ptr );
00853
00854
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
00943 png_read_update_info ( png_ptr, info_ptr );
00944
00945
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
00955
00956
00957
00958
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
00972
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 )
00987 {
00988 scaleQuotient *= 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
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
01022
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 )
01037 {
01038 scaleQuotient *= 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
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
01072
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;
01086
01087 img.resize ( wid, hig );
01088 if ( magickImage.type() != Magick::GrayscaleType )
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
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
01124
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;
01140
01141 img.resize ( wid, hig );
01142 if ( magickImage.type() != Magick::GrayscaleType )
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
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