diff --git a/src/config/tnlParameterContainer.cpp b/src/config/tnlParameterContainer.cpp index 7e9eea94b1d147b5eb9d2200e547676b19d39f08..6483d3dbe2faed4763eea4dd230bcb9540bd9e0c 100644 --- a/src/config/tnlParameterContainer.cpp +++ b/src/config/tnlParameterContainer.cpp @@ -184,7 +184,7 @@ parseCommandLine( int argc, char* argv[], if( strcmp( _option, "--help" ) == 0 ) { config_description.printUsage( argv[ 0 ] ); - continue; + return true; } const char* option = _option + 2; const tnlConfigEntryBase* entry; diff --git a/src/core/io/tnlJPEGImage.h b/src/core/io/tnlJPEGImage.h new file mode 100644 index 0000000000000000000000000000000000000000..8e607b8692bef8deac31d550f2ebfcb2ae6931ac --- /dev/null +++ b/src/core/io/tnlJPEGImage.h @@ -0,0 +1,91 @@ +/*************************************************************************** + tnlJPEGImage.h - description + ------------------- + begin : Jul 25, 2015 + copyright : (C) 2015 by Tomas Oberhuber + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef TNLJPEGIMAGE_H +#define TNLJPEGIMAGE_H + +#include <tnlConfig.h> + +#ifdef HAVE_JPEG_H +#include <jpeglib.h> +#endif + +#include <core/tnlString.h> +#include <core/io/tnlImage.h> +#include <core/io/tnlRegionOfInterest.h> + +template< typename Index = int > +class tnlJPEGImage : public tnlImage< Index > +{ + public: + + typedef Index IndexType; + + tnlJPEGImage(); + + bool openForRead( const tnlString& fileName ); + + template< typename Real, + typename Device, + typename Vector > + bool read( const tnlRegionOfInterest< Index > roi, + const tnlGrid< 2, Real, Device, Index >& grid, + Vector& vector ); + + template< typename Real, + typename Device > + bool openForWrite( const tnlString& fileName, + tnlGrid< 2, Real, Device, Index >& grid ); + + template< typename Real, + typename Device, + typename Vector > + bool write( const tnlGrid< 2, Real, Device, Index >& grid, + Vector& vector ); + + void close(); + + ~tnlJPEGImage(); + + protected: + + bool readHeader(); + + template< typename Real, + typename Device > + bool writeHeader( const tnlGrid< 2, Real, Device, Index >& grid ); + + FILE* file; + + bool fileOpen; + +#ifdef HAVE_JPEG_H + struct my_error_mgr + { + jpeg_error_mgr pub; + jmp_buf setjmp_buffer; + }; + + jpeg_decompress_struct cinfo; +#endif +}; + +#include <core/io/tnlJPEGImage_impl.h> + + +#endif /* TNLJPEGIMAGE_H */ + diff --git a/src/core/io/tnlJPEGImage_impl.h b/src/core/io/tnlJPEGImage_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..9a1c5036a97bfde066da0476cc426833c15f00d3 --- /dev/null +++ b/src/core/io/tnlJPEGImage_impl.h @@ -0,0 +1,359 @@ +/*************************************************************************** + tnlJPEGImage_impl.h - description + ------------------- + begin : Jul 25, 2015 + copyright : (C) 2015 by Tomas Oberhuber + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef TNLJPEGIMAGE_IMPL_H +#define TNLJPEGIMAGE_IMPL_H + +#include <core/io/tnlJPEGImage.h" + +template< typename Index > +tnlJPEGImage< Index >:: +tnlJPEGImage() : + fileOpen( false ) +{ +} + +template< typename Index > +bool +tnlJPEGImage< Index >:: +readHeader() +{ +#ifdef HAVE_PNG_H + /*** + * Check if it is a PNG image. + */ + const int headerSize( 8 ); + png_byte header[ headerSize ]; + if( fread( header, sizeof( char ), headerSize, this->file ) != headerSize ) + { + cerr << "I am not able to read PNG image header." << endl; + return false; + } + bool isPNG = !png_sig_cmp( header, 0, headerSize ); + if( ! isPNG ) + return false; + + /**** + * Allocate necessary memory + */ + this->png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL ); + if( !this->png_ptr ) + return false; + + this->info_ptr = png_create_info_struct( this->png_ptr ); + if( !this->info_ptr ) + { + png_destroy_read_struct( &this->png_ptr, + ( png_infopp ) NULL, + ( png_infopp ) NULL ); + return false; + } + + this->end_info = png_create_info_struct( this->png_ptr ); + if( !this->end_info ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + ( png_infopp ) NULL ); + return false; + } + + /*** + * Prepare the long jump back from libpng. + */ + if( setjmp(png_jmpbuf( this->png_ptr ) ) ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + &end_info ); + return false; + } + png_init_io( this->png_ptr, this->file ); + png_set_sig_bytes( this->png_ptr, headerSize ); + + /**** + * Read the header + */ + png_read_png( this->png_ptr, this->info_ptr, PNG_TRANSFORM_IDENTITY, NULL ); + this->height = ( Index ) png_get_image_height( this->png_ptr, this->info_ptr ); + this->width = ( Index ) png_get_image_width( this->png_ptr, this->info_ptr ); + this->bit_depth = png_get_bit_depth( this->png_ptr, this->info_ptr ); + this->color_type = png_get_color_type( this->png_ptr, this->info_ptr ); + cout << this->height << " x " << this->width << endl; + return true; +#else + cerr << "TNL was not compiled with support of PNG. You may still use PGM format." << endl; + return false; +#endif +} + +template< typename Index > +bool +tnlJPEGImage< Index >:: +openForRead( const tnlString& fileName ) +{ + this->close(); + this->file = fopen( fileName.getString(), "r" ); + if( ! this->file ) + { + cerr << "Unable to open the file " << fileName << endl; + return false; + } + this->fileOpen = true; + if( ! readHeader() ) + return false; + return true; +} + +template< typename Index > + template< typename Real, + typename Device, + typename Vector > +bool +tnlJPEGImage< Index >:: +read( const tnlRegionOfInterest< Index > roi, + const tnlGrid< 2, Real, Device, Index >& grid, + Vector& vector ) +{ +#ifdef HAVE_PNG_H + typedef tnlGrid< 2, Real, Device, Index > GridType; + typedef typename GridType::CoordinatesType CoordinatesType; + + /*** + * Prepare the long jump back from libpng. + */ + if( setjmp(png_jmpbuf( this->png_ptr ) ) ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + &this->end_info ); + return false; + } + + png_bytepp row_pointers = png_get_rows( this->png_ptr, this->info_ptr ); + + Index i, j; + for( i = 0; i < this->height; i ++ ) + { + for( j = 0; j < this->width; j ++ ) + { + if( !roi.isIn( i, j ) ) + continue; + + Index cellIndex = grid.getCellIndex( CoordinatesType( j - roi.getLeft(), + roi.getBottom() - 1 - i ) ); + unsigned char char_color[ 4 ]; + unsigned int int_color[ 4 ]; + switch( this->color_type ) + { + case PNG_COLOR_TYPE_GRAY: + if( this->bit_depth == 8 ) + { + char_color[ 0 ] = row_pointers[ i ][ j ]; + Real value = char_color[ 0 ] / ( Real ) 255.0; + vector.setElement( cellIndex, value ); + } + if( this->bit_depth == 16 ) + { + int_color[ 0 ] = row_pointers[ i ][ j ]; + Real value = int_color[ 0 ] / ( Real ) 65535.0; + vector.setElement( cellIndex, value ); + } + break; + case PNG_COLOR_TYPE_RGB: + if( this->bit_depth == 8 ) + { + char_color[ 0 ] = row_pointers[ i ][ 3 * j ]; + char_color[ 1 ] = row_pointers[ i ][ 3 * j + 1 ]; + char_color[ 2 ] = row_pointers[ i ][ 3 * j + 2 ]; + Real r = char_color[ 0 ] / ( Real ) 255.0; + Real g = char_color[ 1 ] / ( Real ) 255.0; + Real b = char_color[ 2 ] / ( Real ) 255.0; + Real value = 0.2989 * r + 0.5870 * g + 0.1140 * b; + vector.setElement( cellIndex, value ); + } + if( this->bit_depth == 16 ) + { + int_color[ 0 ] = row_pointers[ i ][ 3 * j ]; + int_color[ 1 ] = row_pointers[ i ][ 3 * j + 1 ]; + int_color[ 2 ] = row_pointers[ i ][ 3 * j + 2 ]; + Real r = int_color[ 0 ] / ( Real ) 65535.0; + Real g = int_color[ 1 ] / ( Real ) 66355.0; + Real b = int_color[ 2 ] / ( Real ) 65535.0; + Real value = 0.2989 * r + 0.5870 * g + 0.1140 * b; + vector.setElement( cellIndex, value ); + } + break; + default: + cerr << "Unknown PNG color type." << endl; + return false; + } + } + } + return true; +#else + cerr << "TNL was not compiled with support of PNG. You may still use PGM format." << endl; + return false; +#endif +} + +template< typename Index > + template< typename Real, + typename Device > +bool +tnlJPEGImage< Index >:: +writeHeader( const tnlGrid< 2, Real, Device, Index >& grid ) +{ +#ifdef HAVE_PNG_H + this->png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL ); + if( !png_ptr ) + return false; + + this->info_ptr = png_create_info_struct( this->png_ptr ); + if( !this->info_ptr ) + { + png_destroy_write_struct( &this->png_ptr, + NULL); + return false; + } + + /*** + * Prepare the long jump back from libpng. + */ + if( setjmp(png_jmpbuf( this->png_ptr ) ) ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + &this->end_info ); + return false; + } + + /**** + * Set the zlib compression level + */ + //png_set_compression_level( this->png_ptr, Z_BEST_COMPRESSION ); + + const int bitDepth( 8 ); + png_set_IHDR( this->png_ptr, + this->info_ptr, + grid.getDimensions().x(), + grid.getDimensions().y(), + 8, //bitDepth, + PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT ); + png_init_io( this->png_ptr, this->file ); + png_write_info( png_ptr, info_ptr ); + +#else + cerr << "TNL was not compiled with support of PNG. You may still use PGM format." << endl; + return false; +#endif +} + +template< typename Index > + template< typename Real, + typename Device > +bool +tnlJPEGImage< Index >:: +openForWrite( const tnlString& fileName, + tnlGrid< 2, Real, Device, Index >& grid ) +{ + this->close(); + this->file = fopen( fileName.getString(), "w" ); + if( ! this->file ) + { + cerr << "Unable to open the file " << fileName << endl; + return false; + } + this->fileOpen = true; + if( ! writeHeader( grid ) ) + return false; + return true; +} + +template< typename Index > + template< typename Real, + typename Device, + typename Vector > +bool +tnlJPEGImage< Index >:: +write( const tnlGrid< 2, Real, Device, Index >& grid, + Vector& vector ) +{ + typedef tnlGrid< 2, Real, Device, Index > GridType; + typedef typename GridType::CoordinatesType CoordinatesType; + + /*** + * Prepare the long jump back from libpng. + */ + if( setjmp(png_jmpbuf( this->png_ptr ) ) ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + &this->end_info ); + return false; + } + + Index i, j; + png_bytep row = new png_byte[ 3 * grid.getDimensions().x() ]; + for( i = 0; i < grid.getDimensions().y(); i ++ ) + { + for( j = 0; j < grid.getDimensions().x(); j ++ ) + { + Index cellIndex = grid.getCellIndex( CoordinatesType( j, + grid.getDimensions().y() - 1 - i ) ); + + row[ j ] = 255 * vector.getElement( cellIndex ); + } + png_write_row( this->png_ptr, row ); + } + //png_set_rows( this->png_ptr, this->info_ptr, row_pointers ); + //png_write_png( this->png_ptr, this->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + delete[] row; + return true; +} + + +template< typename Index > +void +tnlJPEGImage< Index >:: +close() +{ + if( this->fileOpen ) + fclose( file ); + this->fileOpen = false; +} + +template< typename Index > +tnlJPEGImage< Index >:: +~tnlJPEGImage() +{ + close(); +} + + + +#endif /* TNLJPEGIMAGE_IMPL_H */ + diff --git a/src/core/io/tnlPNGImage.h b/src/core/io/tnlPNGImage.h index f28fc095fd08c101a85db00ff05ca06d2775a325..b907655f2b2be3a5f4275eb3f2bb53233e388237 100644 --- a/src/core/io/tnlPNGImage.h +++ b/src/core/io/tnlPNGImage.h @@ -49,8 +49,7 @@ class tnlPNGImage : public tnlImage< Index > template< typename Real, typename Device > bool openForWrite( const tnlString& fileName, - tnlGrid< 2, Real, Device, Index >& grid, - bool binary = true ); + tnlGrid< 2, Real, Device, Index >& grid ); template< typename Real, typename Device, @@ -68,8 +67,7 @@ class tnlPNGImage : public tnlImage< Index > template< typename Real, typename Device > - bool writeHeader( const tnlGrid< 2, Real, Device, Index >& grid, - bool binary ); + bool writeHeader( const tnlGrid< 2, Real, Device, Index >& grid ); FILE* file; diff --git a/src/core/io/tnlPNGImage_impl.h b/src/core/io/tnlPNGImage_impl.h index 13b12bbb789a874eaf8f91ce3f1e060723664def..04ca727ddea10b19c63d9d79c33b10575b605a5d 100644 --- a/src/core/io/tnlPNGImage_impl.h +++ b/src/core/io/tnlPNGImage_impl.h @@ -18,9 +18,7 @@ #ifndef TNLPNGIMAGE_IMPL_H #define TNLPNGIMAGE_IMPL_H -#ifdef HAVE_PNG_H -#include <png.h> -#endif +#include "tnlPNGImage.h" template< typename Index > tnlPNGImage< Index >:: @@ -94,8 +92,8 @@ readHeader() * Read the header */ png_read_png( this->png_ptr, this->info_ptr, PNG_TRANSFORM_IDENTITY, NULL ); - this->height = this->info_ptr->height; //( Index ) png_get_image_height( this->png_ptr, this->info_ptr ); - this->width = this->info_ptr->width; //( Index ) png_get_image_width( this->png_ptr, this->info_ptr ); + this->height = ( Index ) png_get_image_height( this->png_ptr, this->info_ptr ); + this->width = ( Index ) png_get_image_width( this->png_ptr, this->info_ptr ); this->bit_depth = png_get_bit_depth( this->png_ptr, this->info_ptr ); this->color_type = png_get_color_type( this->png_ptr, this->info_ptr ); cout << this->height << " x " << this->width << endl; @@ -221,10 +219,9 @@ template< typename Index > typename Device > bool tnlPNGImage< Index >:: -writeHeader( const tnlGrid< 2, Real, Device, Index >& grid, - bool binary ) +writeHeader( const tnlGrid< 2, Real, Device, Index >& grid ) { -#idef HAVE_PNG_H +#ifdef HAVE_PNG_H this->png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, @@ -240,11 +237,39 @@ writeHeader( const tnlGrid< 2, Real, Device, Index >& grid, return false; } + /*** + * Prepare the long jump back from libpng. + */ + if( setjmp(png_jmpbuf( this->png_ptr ) ) ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + &this->end_info ); + return false; + } + + /**** + * Set the zlib compression level + */ + //png_set_compression_level( this->png_ptr, Z_BEST_COMPRESSION ); + + const int bitDepth( 8 ); + png_set_IHDR( this->png_ptr, + this->info_ptr, + grid.getDimensions().x(), + grid.getDimensions().y(), + 8, //bitDepth, + PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT ); + png_init_io( this->png_ptr, this->file ); + png_write_info( png_ptr, info_ptr ); + #else cerr << "TNL was not compiled with support of PNG. You may still use PGM format." << endl; return false; -#endif - +#endif } template< typename Index > @@ -268,6 +293,48 @@ openForWrite( const tnlString& fileName, return true; } +template< typename Index > + template< typename Real, + typename Device, + typename Vector > +bool +tnlPNGImage< Index >:: +write( const tnlGrid< 2, Real, Device, Index >& grid, + Vector& vector ) +{ + typedef tnlGrid< 2, Real, Device, Index > GridType; + typedef typename GridType::CoordinatesType CoordinatesType; + + /*** + * Prepare the long jump back from libpng. + */ + if( setjmp(png_jmpbuf( this->png_ptr ) ) ) + { + png_destroy_read_struct( &this->png_ptr, + &this->info_ptr, + &this->end_info ); + return false; + } + + Index i, j; + png_bytep row = new png_byte[ 3 * grid.getDimensions().x() ]; + for( i = 0; i < grid.getDimensions().y(); i ++ ) + { + for( j = 0; j < grid.getDimensions().x(); j ++ ) + { + Index cellIndex = grid.getCellIndex( CoordinatesType( j, + grid.getDimensions().y() - 1 - i ) ); + + row[ j ] = 255 * vector.getElement( cellIndex ); + } + png_write_row( this->png_ptr, row ); + } + //png_set_rows( this->png_ptr, this->info_ptr, row_pointers ); + //png_write_png( this->png_ptr, this->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + delete[] row; + return true; +} + template< typename Index > void diff --git a/tools/src/tnl-image-converter.cpp b/tools/src/tnl-image-converter.cpp index c4d3ba32777851deabcef578f0c9c6beab7a1ef4..b0dabea5455e15d4df63c6953ec6bf6875e9905b 100644 --- a/tools/src/tnl-image-converter.cpp +++ b/tools/src/tnl-image-converter.cpp @@ -21,6 +21,7 @@ #include <mesh/tnlGrid.h> #include <core/io/tnlPGMImage.h> #include <core/io/tnlPNGImage.h> +#include <core/io/tnlJPEGImage.h> #include <core/io/tnlRegionOfInterest.h> void configSetup( tnlConfigDescription& config ) @@ -70,61 +71,87 @@ bool processImages( const tnlParameterContainer& parameters ) tnlRegionOfInterest< int > roi; for( int i = 0; i < inputImages.getSize(); i++ ) { - const tnlString& fileName = inputImages[ i ]; - cout << "Processing image file " << fileName << "... "; - tnlPGMImage< int > pgmImage; - if( pgmImage.openForRead( fileName ) ) - { - cout << "PGM format detected ..."; - if( i == 0 ) - { - if( ! roi.setup( parameters, &pgmImage ) ) - return false; - setGrid( roi, grid, verbose ); - vector.setSize( grid.getNumberOfCells() ); - cout << "Writing grid to file " << meshFile << endl; - grid.save( meshFile ); - } - else - if( ! roi.check( &pgmImage ) ) - return false; - if( ! pgmImage.read( roi, grid, vector ) ) - return false; - tnlString outputFileName( fileName ); - RemoveFileExtension( outputFileName ); - outputFileName += ".tnl"; - cout << "Writing image data to " << outputFileName << endl; - vector.save( outputFileName ); - pgmImage.close(); - continue; - } - tnlPNGImage< int > pngImage; - if( pngImage.openForRead( fileName ) ) - { - cout << "PNG format detected ..."; - if( i == 0 ) - { - if( ! roi.setup( parameters, &pngImage ) ) - return false; - setGrid( roi, grid, verbose ); - vector.setSize( grid.getNumberOfCells() ); - cout << "Writing grid to file " << meshFile << endl; - grid.save( meshFile ); - } - else - if( ! roi.check( &pgmImage ) ) - return false; - if( ! pngImage.read( roi, grid, vector ) ) - return false; - tnlString outputFileName( fileName ); - RemoveFileExtension( outputFileName ); - outputFileName += ".tnl"; - cout << "Writing image data to " << outputFileName << endl; - vector.save( outputFileName ); - pgmImage.close(); - continue; - } - } + const tnlString& fileName = inputImages[ i ]; + cout << "Processing image file " << fileName << "... "; + tnlPGMImage< int > pgmImage; + if( pgmImage.openForRead( fileName ) ) + { + cout << "PGM format detected ..."; + if( i == 0 ) + { + if( ! roi.setup( parameters, &pgmImage ) ) + return false; + setGrid( roi, grid, verbose ); + vector.setSize( grid.getNumberOfCells() ); + cout << "Writing grid to file " << meshFile << endl; + grid.save( meshFile ); + } + else + if( ! roi.check( &pgmImage ) ) + return false; + if( ! pgmImage.read( roi, grid, vector ) ) + return false; + tnlString outputFileName( fileName ); + RemoveFileExtension( outputFileName ); + outputFileName += ".tnl"; + cout << "Writing image data to " << outputFileName << endl; + vector.save( outputFileName ); + pgmImage.close(); + continue; + } + tnlPNGImage< int > pngImage; + if( pngImage.openForRead( fileName ) ) + { + cout << "PNG format detected ..."; + if( i == 0 ) + { + if( ! roi.setup( parameters, &pngImage ) ) + return false; + setGrid( roi, grid, verbose ); + vector.setSize( grid.getNumberOfCells() ); + cout << "Writing grid to file " << meshFile << endl; + grid.save( meshFile ); + } + else + if( ! roi.check( &pgmImage ) ) + return false; + if( ! pngImage.read( roi, grid, vector ) ) + return false; + tnlString outputFileName( fileName ); + RemoveFileExtension( outputFileName ); + outputFileName += ".tnl"; + cout << "Writing image data to " << outputFileName << endl; + vector.save( outputFileName ); + pgmImage.close(); + continue; + } + tnlJPEGImage< int > jpegImage; + if( jpegImage.openForRead( fileName ) ) + { + cout << "JPEG format detected ..."; + if( i == 0 ) + { + if( ! roi.setup( parameters, &pngImage ) ) + return false; + setGrid( roi, grid, verbose ); + vector.setSize( grid.getNumberOfCells() ); + cout << "Writing grid to file " << meshFile << endl; + grid.save( meshFile ); + } + else + if( ! roi.check( &pgmImage ) ) + return false; + if( ! pngImage.read( roi, grid, vector ) ) + return false; + tnlString outputFileName( fileName ); + RemoveFileExtension( outputFileName ); + outputFileName += ".tnl"; + cout << "Writing image data to " << outputFileName << endl; + vector.save( outputFileName ); + pgmImage.close(); + continue; + } + } } bool processTNLFiles( const tnlParameterContainer& parameters ) @@ -159,6 +186,17 @@ bool processTNLFiles( const tnlParameterContainer& parameters ) image.openForWrite( outputFileName, grid, true ); image.write( grid, vector ); image.close(); + continue; + } + if( imageFormat == "png" ) + { + tnlPNGImage< int > image; + tnlString outputFileName( fileName ); + RemoveFileExtension( outputFileName ); + outputFileName += ".png"; + image.openForWrite( outputFileName, grid ); + image.write( grid, vector ); + image.close(); } } }