123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- #include <core/image/ImageFile.h>
- #include <core/image/ImageT.h>
- #include <core/image/ColorImageT.h>
- #include <core/image/Convert.h>
- #include <core/basics/stringutils.h>
- #include <iostream>
- #ifdef NICE_USELIB_LIBMAGICK
- #include <Magick++.h>
- #endif
- #ifdef NICE_USELIB_JPG
- // a little hack to handle the incompatible INT32 definitions in qt3 and libjpeg
- #define INT32 INT32_ALTERNATIVE
- extern "C" {
- #include <jpeglib.h>
- }
- #undef INT32
- #endif
- namespace NICE {
- template<class P> class ColorImageT;
- #ifdef NICE_USELIB_LIBMAGICK
- template<>
- void ImageFile::readerMagick ( GrayColorImageCommonImplementationT<unsigned char> *image );
- template<>
- void ImageFile::writerMagick ( const GrayColorImageCommonImplementationT<unsigned char> *image ) const;
- #endif
- template<class P>
- void ImageFile::reader ( GrayColorImageCommonImplementationT<P> *image )
- {
- switch ( fileType() )
- {
- #ifdef NICE_USELIB_PNG
- case ImageFile::PNG:
- readerPNG ( image );
- break;
- #endif // NICE_USELIB_PNG
- #ifdef NICE_USELIB_JPG
- case ImageFile::JPG:
- readerJPG ( image );
- break;
- #endif // NICE_USELIB_JPG
- case ImageFile::PPM_RAW:
- case ImageFile::PGM_RAW:
- readerPXM ( image );
- break;
- default:
- #ifdef NICE_USELIB_LIBMAGICK
- try {
- readerMagick ( image );
- } catch ( Magick::ErrorBlob & error ) {
- fthrow ( ImageException, std::string ( "Format not yet implemented. (libMagick++ error: " ) + std::string ( error.what() ) + std::string ( ")" ) );
- }
- #else
- fthrow ( ImageException, "Format not yet implemented. (try using libMagick++)" );
- #endif
- }
- }
- template<class P>
- void ImageFile::writer ( const GrayColorImageCommonImplementationT<P> *image ) const
- {
- switch ( fileType() )
- {
- case ImageFile::PNG:
- #ifdef NICE_USELIB_PNG
- writerPNG ( image );
- #else
- #ifdef NICE_USELIB_LIBMAGICK
- try {
- writerMagick ( image );
- } catch ( Magick::Exception ) {
- fthrow ( ImageException, "Format not yet implemented." );
- }
- #else
- fthrow ( ImageException, "Format not yet implemented. (try using libMagick)" );
- #endif
- #endif
- break;
- case ImageFile::JPG:
- #ifdef NICE_USELIB_JPG
- writerJPG ( image );
- #else
- fthrow ( ImageException, "JPEG format not supported." );
- #endif
- break;
- case ImageFile::PPM_RAW:
- if ( image->channels() == 3 )
- {
- writerPXM ( image );
- }
- else
- {
- ColorImageT<P> *rgb = grayToRGB ( *reinterpret_cast<const ImageT<P>*> ( image ) );
- writerPXM ( rgb );
- delete rgb;
- }
- break;
- case ImageFile::PGM_RAW:
- if ( image->channels() == 1 )
- writerPXM ( image );
- else {
- ImageT<P> *gray = rgbToGray ( *reinterpret_cast<const ColorImageT<P>*> ( image ) );
- writerPXM ( gray );
- delete gray;
- }
- break;
- default:
- #ifdef NICE_USELIB_LIBMAGICK
- try {
- writerMagick ( image );
- } catch ( Magick::Exception ) {
- fthrow ( ImageException, "Format not yet implemented." );
- }
- #else
- fthrow ( ImageException, "Format not yet implemented. (try using libMagick)" );
- #endif
- }
- }
- template <class P>
- void ImageFile::readerPXM ( GrayColorImageCommonImplementationT<P> *image )
- {
- using namespace std;
- // open the file
- ifstream file ( filename.c_str(), ios::binary );
- // error handling
- if ( !file.good() )
- {
- fthrow ( ImageException, string ( "readPXM: Cannot open " ) + filename );
- }
- if ( datapos == 0 )
- getPXMHeader();
- if ( fileheader.width != image->widthInline() || fileheader.height != image->heightInline() ) {
- image->resize ( fileheader.width, fileheader.height );
- }
- file.seekg ( datapos );
- int srcbytedepth = fileheader.bitdepth / 8;
- if ( srcbytedepth == image->bytedepth() ) { // same bit depth
- if ( fileformat == PPM_RAW || fileformat == PGM_RAW )
- {
- // simple case just write into image
- if ( fileheader.channel == image->channels() )
- {
- for ( int y = 0; y < fileheader.height; y++ )
- {
- file.read ( reinterpret_cast<char*>
- ( image->getPixelPointerY ( y ) ), fileheader.width*fileheader.channel*srcbytedepth );
- }
- }
- // it is a gray image but should be converted to a rgb image
- else if ( fileheader.channel == 1 )
- {
- for ( int y = 0; y < fileheader.height; y++ ) {
- P *line = new P[fileheader.width];
- file.read ( reinterpret_cast<char *> ( line ), fileheader.width );
- P *target = image->getPixelPointerY ( y );
- P *src = line;
- for ( int x = 0; x < fileheader.width; x++, src++ ) {
- for ( int i = 0;i < image->channels();i++, target++ )
- *target = *src;
- delete [] line;
- }
- }
- }
- // it is a rgb image that should be converted to a gray image
- else if ( fileheader.channel == 3 && image->channels() == 1 )
- {
- ColorImageT<P> rgb ( fileheader.width, fileheader.height );
- for ( int y = 0; y < fileheader.height; y++ )
- {
- file.read ( reinterpret_cast<char*>
- ( rgb.getPixelPointerY ( y ) ), fileheader.width*fileheader.channel*srcbytedepth );
- }
- rgbToGray ( rgb, dynamic_cast<ImageT<P> *> ( image ) );
- }
- else
- {
- fthrow ( ImageException, "Format (channels) not yet implemented." );
- }
- } else {
- fthrow ( ImageException, "Format not yet implemented." );
- }
- }
- // different bitdephs
- else
- {
- if ( fileformat == PPM_RAW || fileformat == PGM_RAW ) {
- if ( fileheader.channel == 1 || ( fileheader.channel == 3 && image->channels() == 3 ) ) { // have to cast
- for ( int y = 0; y < fileheader.height; y++ ) {
- Ipp8u *line = new Ipp8u[fileheader.width*fileheader.channel*srcbytedepth];
- file.read ( reinterpret_cast<char *> ( line ), fileheader.width*fileheader.channel*srcbytedepth );
- P *target = image->getPixelPointerY ( y );
- Ipp8u *src = line;
- if ( srcbytedepth == 1 ) {
- for ( int x = 0; x < fileheader.width; x++ ) {
- for ( int i = 0;i < fileheader.channel;i++, src++, target++ )
- *target = static_cast<P> ( *src );
- }
- } else {
- for ( int x = 0; x < fileheader.width; x++ ) {
- for ( int i = 0;i < fileheader.channel;i++, src += srcbytedepth, target++ )
- * target = static_cast<P> ( *reinterpret_cast<Ipp16u *> ( src ) );
- }
- }
- delete [] line;
- }
- } else if ( fileheader.channel == 3 && image->channels() == 1 ) { // have to cast and to convert
- ColorImageT<P> rgb ( fileheader.width, fileheader.height );
- for ( int y = 0; y < fileheader.height; y++ ) {
- Ipp8u *line = new Ipp8u[fileheader.width*fileheader.channel*srcbytedepth];
- file.read ( reinterpret_cast<char *> ( line ), fileheader.width*fileheader.channel*srcbytedepth );
- P *target = rgb.getPixelPointerY ( y );
- Ipp8u *src = line;
- if ( srcbytedepth == 1 ) {
- for ( int x = 0; x < fileheader.width; x++ ) {
- for ( int i = 0;i < fileheader.channel;i++, src++, target++ )
- *target = static_cast<P> ( *src );
- }
- } else {
- for ( int x = 0; x < fileheader.width; x++ ) {
- for ( int i = 0;i < fileheader.channel;i++, src += srcbytedepth, target++ )
- * target = static_cast<P> ( *reinterpret_cast<Ipp16u *> ( src ) );
- }
- }
- delete [] line;
- }
- rgbToGray ( rgb, dynamic_cast<ImageT<P> *> ( image ) );
- } else {
- fthrow ( ImageException, "Format (channels) not yet implemented." );
- }
- } else {
- fthrow ( ImageException, "Format not yet implemented." );
- }
- }
- }
- #ifdef NICE_USELIB_LIBMAGICK
- template<class P>
- void ImageFile::readerMagick ( GrayColorImageCommonImplementationT<P> *image )
- {
- fthrow ( ImageException, "Format not yet implemented (only available for standard images)." );
- }
- template<class P>
- void ImageFile::writerMagick ( const GrayColorImageCommonImplementationT<P> *image ) const
- {
- fthrow ( ImageException, "Format not yet implemented (only available for standard images)." );
- }
- #endif
- template <class P>
- void ImageFile::writerPXM ( const GrayColorImageCommonImplementationT<P> *image ) const {
- using namespace std;
- ofstream file ( filename.c_str(), ios::binary );
- if ( image->channels() == 1 )
- file << "P5" << endl;
- else if ( image->channels() == 3 )
- file << "P6" << endl;
- else {
- string msg = "Cannot write a ";
- msg += itostr ( image->channels() );
- msg += "-channel format. This is not yet implemented.";
- fthrow ( ImageException, msg );
- }
- file << image->widthInline() << " " << image->heightInline() << endl;
- file << static_cast<int> ( std::pow ( 2.0, image->bitdepth() ) - 1 ) << endl;
- for ( int y = 0; y < image->heightInline(); y++ ) {
- file.write ( reinterpret_cast<const char *> ( image->getPixelPointerY ( y ) ), image->widthInline() *image->channels() *image->bytedepth() );
- }
- file.close();
- }
- #ifdef NICE_USELIB_PNG
- template<class P>
- void ImageFile::readerPNG ( GrayColorImageCommonImplementationT<P> *image )
- {
- FILE* pFile;
- // open image file
- if ( ( pFile = fopen ( filename.c_str(), "rb" ) ) == NULL ) {
- fthrow ( ImageException, "ImageFile::readerPNG: Cannot open " + filename );
- }
- // read header
- const int headersize = 8; // 8 is the maximum size that can be checked
- png_byte header[headersize];
- fread ( header, 1, headersize, pFile );
- if ( png_sig_cmp ( header, 0, headersize ) ) {
- fclose ( pFile );
- fthrow ( ImageException, "Image is not a PNG file." );
- }
- /* initialize stuff */
- png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
- if ( !png_ptr ) {
- fclose ( pFile );
- fthrow ( ImageException, "png_create_read_struct failed" );
- }
- png_infop info_ptr = png_create_info_struct ( png_ptr );
- if ( !info_ptr ) {
- fclose ( pFile );
- fthrow ( ImageException, "png_create_info_struct failed" );
- }
- if ( setjmp ( png_jmpbuf ( png_ptr ) ) ) {
- fclose ( pFile );
- fthrow ( ImageException, "Error during init_io" );
- }
- png_init_io ( png_ptr, pFile );
- png_set_sig_bytes ( png_ptr, headersize );
- png_read_info ( png_ptr, info_ptr );
- int width = png_get_image_width(png_ptr, info_ptr);
- int height = png_get_image_height(png_ptr, info_ptr);
- png_byte color_type = png_get_color_type(png_ptr, info_ptr);
- png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
- // resize image if necessary
- if ( width != image->widthInline() || height != image->heightInline() ) {
- image->resize ( width, height );
- }
- //int number_of_passes = png_set_interlace_handling(png_ptr);
- /** expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
- transparency chunks to full alpha channel; strip 16-bit-per-sample
- images to 8 bits per sample; and convert grayscale to RGB[A] */
- if ( color_type == PNG_COLOR_TYPE_PALETTE )
- png_set_expand ( png_ptr );
- if ( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
- png_set_expand ( png_ptr );
- if ( png_get_valid ( png_ptr, info_ptr, PNG_INFO_tRNS ) )
- png_set_expand ( png_ptr );
- if ( image->bitdepth() == 8 && bit_depth == 16 ) {
- png_set_strip_16 ( png_ptr );
- }
- if ( image->bitdepth() == 16 && bit_depth == 8 ) {
- fthrow ( ImageException, "convertion from 16 to 8 bit not implemented." );
- }
- switch ( image->channels() ) {
- case 1:
- if ( color_type == PNG_COLOR_TYPE_RGBA ||
- color_type == PNG_COLOR_TYPE_RGB ) {
- png_set_rgb_to_gray_fixed ( png_ptr, 1, -1, -1 );
- }
- if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
- png_set_strip_alpha ( png_ptr );
- break;
- case 3:
- if ( color_type == PNG_COLOR_TYPE_RGBA )
- png_set_strip_alpha ( png_ptr );
- if ( color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
- png_set_gray_to_rgb ( png_ptr );
- break;
- case 4:
- break;
- default:
- fthrow ( ImageException, "No or invalid color image->channels()" );
- break;
- }
- png_read_update_info ( png_ptr, info_ptr );
- // read file
- if ( setjmp ( png_jmpbuf ( png_ptr ) ) ) {
- fclose ( pFile );
- fthrow ( ImageException, "Error during read_image" );
- }
- png_bytep * row_pointers = new png_bytep[height];
- for ( int y = 0; y < height; y++ )
- row_pointers[y] = reinterpret_cast<png_bytep> ( image->getPixelPointerY ( y ) );
- png_read_image ( png_ptr, row_pointers );
- delete [] row_pointers;
- png_destroy_read_struct ( &png_ptr, &info_ptr, NULL );
- fclose ( pFile );
- }
- template<>
- void ImageFile::readerPNG ( GrayColorImageCommonImplementationT<Ipp32f> *image );
- template<class P>
- void ImageFile::writerPNG ( const GrayColorImageCommonImplementationT<P> *image ) const
- {
- FILE *pfile;
- // open image file
- if ( ( pfile = fopen ( filename.c_str(), "wb" ) ) == NULL )
- fthrow ( ImageException, "ImageFile::writerPNG: Cannot write " + filename );
- png_structp png_ptr = png_create_write_struct ( PNG_LIBPNG_VER_STRING, NULL,
- NULL, NULL );
- if ( !png_ptr ) {
- fclose ( pfile );
- fthrow ( ImageException, "png_create_write_struct failed" );
- }
- png_infop info_ptr = png_create_info_struct ( png_ptr );
- if ( !info_ptr ) {
- png_destroy_write_struct ( &png_ptr, ( png_infopp ) NULL );
- fclose ( pfile );
- fthrow ( ImageException, "png_create_info_struct failed" );
- }
- if ( setjmp ( png_jmpbuf ( png_ptr ) ) ) {
- png_destroy_write_struct ( &png_ptr, &info_ptr );
- fclose ( pfile );
- fthrow ( ImageException, "Error during write_image" );
- }
- png_init_io ( png_ptr, pfile );
- png_infop png_info_ptr = png_create_info_struct ( png_ptr );
- int bit_depth = image->bitdepth();
- int color_type;
- switch ( image->channels() ) {
- case 1:
- color_type = PNG_COLOR_TYPE_GRAY;
- break;
- case 2:
- color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
- break;
- case 3:
- color_type = PNG_COLOR_TYPE_RGB;
- break;
- case 4:
- color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- default:
- fthrow ( ImageException, "No or invalid color channels" );
- break;
- }
- int interlace_type = PNG_INTERLACE_NONE;
- png_set_IHDR ( png_ptr, png_info_ptr, image->widthInline(), image->heightInline(),
- bit_depth, color_type, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
- /* turn on or off filtering, and/or choose
- specific filters. You can use either a single
- PNG_FILTER_VALUE_NAME or the logical OR of one
- or more PNG_FILTER_NAME masks. */
- png_set_filter ( png_ptr, 0, PNG_FILTER_AVG );
- /* set the zlib compression level */
- //png_set_compression_level ( png_ptr, Z_BEST_COMPRESSION );
- //png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
- /* set other zlib parameters */
- /* png_set_compression_mem_level(png_ptr, 8);
- png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
- png_set_compression_window_bits(png_ptr, 15);
- png_set_compression_buffer_size(png_ptr, 8192);
- png_set_compression_method(png_ptr, 8); */
- png_write_info ( png_ptr, png_info_ptr );
- for ( int y = 0; y < image->heightInline(); y++ ) {
- //const P *prow=image->getPixelPointerY(y);
- png_byte row[image->widthInline() *image->channels() *image->bytedepth() ];
- memcpy ( row, image->getPixelPointerY ( y ), image->widthInline() *image->channels() *image->bytedepth() );
- png_write_row ( png_ptr, row );
- }
- png_write_end ( png_ptr, info_ptr );
- png_destroy_write_struct ( &png_ptr, &info_ptr );
- fclose ( pfile );
- }
- #endif
- #ifdef NICE_USELIB_JPG
- template<class P>
- void ImageFile::readerJPG ( GrayColorImageCommonImplementationT<P> *image )
- {
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- FILE* pFile;
- if ( ( pFile = fopen ( filename.c_str(), "rb" ) ) == NULL )
- fthrow ( ImageException, "ImageFile::readerJPG: Cannot open " + filename );
- cinfo.err = jpeg_std_error ( &jerr );
- jpeg_create_decompress ( &cinfo );
- jpeg_stdio_src ( &cinfo, pFile );
- jpeg_read_header ( &cinfo, FALSE );
- if ( image->channels() != 1 && image->channels() != 3 )
- fthrow ( ImageException, "Format not yet supported" );
- cinfo.out_color_space = image->channels() == 1 ? JCS_GRAYSCALE : JCS_RGB;
- jpeg_start_decompress ( &cinfo );
- int row_stride = cinfo.output_width * cinfo.output_components;
- JSAMPARRAY buffer = ( *cinfo.mem->alloc_sarray ) ( ( j_common_ptr ) & cinfo, JPOOL_IMAGE, row_stride, 1 );
- // resize image if necessary
- int width = cinfo.output_width;
- int height = cinfo.output_height;
- if ( width != image->widthInline() || height != image->heightInline() )
- image->resize ( width, height );
- // Bilddaten zeilenweise einlesen
- for ( int y = 0; y < height; ++y ) {
- if ( !jpeg_read_scanlines ( &cinfo, buffer, 1 ) )
- fthrow ( ImageException, "ImageFile::readerJPG: Some Error occured while reading " + filename );
- if ( sizeof ( P ) == sizeof ( Ipp8u ) )
- memcpy ( image->getPixelPointerY ( y ), buffer[0], width*image->channels() );
- else {
- const Ipp8u* pSrc = buffer[0];
- P* pDst = image->getPixelPointerY ( y );
- for ( int x = 0; x < width*image->channels(); ++x, ++pSrc, ++pDst )
- if ( *pSrc < std::numeric_limits<P>::min() )
- *pDst = std::numeric_limits<P>::min();
- else if ( *pSrc > std::numeric_limits<P>::max() )
- *pDst = std::numeric_limits<P>::max();
- else
- *pDst = static_cast<Ipp8u> ( *pSrc );
- }
- }
- jpeg_finish_decompress ( &cinfo );
- jpeg_destroy_decompress ( &cinfo );
- fclose ( pFile );
- }
- template<class P>
- void ImageFile::writerJPG ( const GrayColorImageCommonImplementationT<P> *image, const int quality ) const
- {
- FILE *pfile;
- if ( ( pfile = fopen ( filename.c_str(), "wb" ) ) == NULL )
- fthrow ( ImageException, "ImageFile::writerJPG: Cannot write " + filename );
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error ( &jerr );
- jpeg_create_compress ( &cinfo );
- jpeg_stdio_dest ( &cinfo, pfile );
- cinfo.image_width = image->widthInline();
- cinfo.image_height = image->heightInline();
- cinfo.input_components = image->channels();
- if ( image->channels() != 1 && image->channels() != 3 )
- fthrow ( ImageException, "Format not yet supported" );
- cinfo.in_color_space = image->channels() == 1 ? JCS_GRAYSCALE : JCS_RGB;
- jpeg_set_defaults ( &cinfo );
- jpeg_set_quality ( &cinfo, quality, TRUE );
- jpeg_start_compress ( &cinfo, TRUE );
- int width = cinfo.image_width;
- int height = cinfo.image_height;
- JSAMPROW row_pointer[1];
- row_pointer[0] = new Ipp8u[width*image->channels() ];
- for ( int y = 0; y < height; ++y ) {
- if ( sizeof ( P ) == sizeof ( Ipp8u ) )
- memcpy ( row_pointer[0], image->getPixelPointerY ( y ), width*image->channels() );
- else {
- const P* pSrc = image->getPixelPointerY ( y );
- Ipp8u* pDst = row_pointer[0];
- for ( int x = 0; x < width*image->channels(); ++x, ++pSrc, ++pDst )
- if ( *pSrc < std::numeric_limits<Ipp8u>::min() )
- *pDst = std::numeric_limits<Ipp8u>::min();
- else if ( *pSrc > std::numeric_limits<Ipp8u>::max() )
- *pDst = std::numeric_limits<Ipp8u>::max();
- else
- *pDst = static_cast<Ipp8u> ( *pSrc );
- }
- jpeg_write_scanlines ( &cinfo, row_pointer, 1 );
- }
- jpeg_finish_compress ( &cinfo );
- fclose ( pfile );
- jpeg_destroy_compress ( &cinfo );
- }
- #endif
- }
|