123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- //
- // Copyright 2012 Christian Henning
- //
- // Distributed under the Boost Software License, Version 1.0
- // See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt
- //
- #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
- #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
- #include <boost/gil/extension/io/png/tags.hpp>
- #include <boost/gil/extension/io/png/detail/base.hpp>
- #include <boost/gil/extension/io/png/detail/supported_types.hpp>
- #include <boost/gil/io/base.hpp>
- #include <boost/gil/io/typedefs.hpp>
- namespace boost { namespace gil {
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(push)
- #pragma warning(disable:4512) //assignment operator could not be generated
- #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
- #endif
- ///
- /// PNG Writer Backend
- ///
- template< typename Device >
- struct writer_backend< Device
- , png_tag
- >
- : public detail::png_struct_info_wrapper
- {
- private:
- using this_t = writer_backend<Device, png_tag>;
- public:
- using format_tag_t = png_tag;
- ///
- /// Constructor
- ///
- writer_backend( const Device& io_dev
- , const image_write_info< png_tag >& info
- )
- : png_struct_info_wrapper( false )
- , _io_dev( io_dev )
- , _info( info )
- {
- // Create and initialize the png_struct with the desired error handler
- // functions. If you want to use the default stderr and longjump method,
- // you can supply NULL for the last three parameters. We also check that
- // the library version is compatible with the one used at compile time,
- // in case we are using dynamically linked libraries. REQUIRED.
- get()->_struct = png_create_write_struct( PNG_LIBPNG_VER_STRING
- , nullptr // user_error_ptr
- , nullptr // user_error_fn
- , nullptr // user_warning_fn
- );
- io_error_if( get_struct() == nullptr
- , "png_writer: fail to call png_create_write_struct()"
- );
- // Allocate/initialize the image information data. REQUIRED
- get()->_info = png_create_info_struct( get_struct() );
- if( get_info() == nullptr )
- {
- png_destroy_write_struct( &get()->_struct
- , nullptr
- );
- io_error( "png_writer: fail to call png_create_info_struct()" );
- }
- // Set error handling. REQUIRED if you aren't supplying your own
- // error handling functions in the png_create_write_struct() call.
- if( setjmp( png_jmpbuf( get_struct() )))
- {
- //free all of the memory associated with the png_ptr and info_ptr
- png_destroy_write_struct( &get()->_struct
- , &get()->_info
- );
- io_error( "png_writer: fail to call setjmp()" );
- }
- init_io( get_struct() );
- }
- protected:
- template< typename View >
- void write_header( const View& view )
- {
- using png_rw_info_t = detail::png_write_support
- <
- typename channel_type<typename get_pixel_type<View>::type>::type,
- typename color_space_type<View>::type
- >;
- // Set the image information here. Width and height are up to 2^31,
- // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
- // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
- // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
- // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
- // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
- // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
- png_set_IHDR( get_struct()
- , get_info()
- , static_cast< png_image_width::type >( view.width() )
- , static_cast< png_image_height::type >( view.height() )
- , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth )
- , static_cast< png_color_type::type >( png_rw_info_t::_color_type )
- , _info._interlace_method
- , _info._compression_type
- , _info._filter_method
- );
- #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
- if( _info._valid_cie_colors )
- {
- png_set_cHRM( get_struct()
- , get_info()
- , _info._white_x
- , _info._white_y
- , _info._red_x
- , _info._red_y
- , _info._green_x
- , _info._green_y
- , _info._blue_x
- , _info._blue_y
- );
- }
- if( _info._valid_file_gamma )
- {
- png_set_gAMA( get_struct()
- , get_info()
- , _info._file_gamma
- );
- }
- #else
- if( _info._valid_cie_colors )
- {
- png_set_cHRM_fixed( get_struct()
- , get_info()
- , _info._white_x
- , _info._white_y
- , _info._red_x
- , _info._red_y
- , _info._green_x
- , _info._green_y
- , _info._blue_x
- , _info._blue_y
- );
- }
- if( _info._valid_file_gamma )
- {
- png_set_gAMA_fixed( get_struct()
- , get_info()
- , _info._file_gamma
- );
- }
- #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
- if( _info._valid_icc_profile )
- {
- #if PNG_LIBPNG_VER_MINOR >= 5
- png_set_iCCP( get_struct()
- , get_info()
- , const_cast< png_charp >( _info._icc_name.c_str() )
- , _info._iccp_compression_type
- , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) )
- , _info._profile_length
- );
- #else
- png_set_iCCP( get_struct()
- , get_info()
- , const_cast< png_charp >( _info._icc_name.c_str() )
- , _info._iccp_compression_type
- , const_cast< png_charp >( & (_info._profile.front()) )
- , _info._profile_length
- );
- #endif
- }
- if( _info._valid_intent )
- {
- png_set_sRGB( get_struct()
- , get_info()
- , _info._intent
- );
- }
- if( _info._valid_palette )
- {
- png_set_PLTE( get_struct()
- , get_info()
- , const_cast< png_colorp >( &_info._palette.front() )
- , _info._num_palette
- );
- }
- if( _info._valid_background )
- {
- png_set_bKGD( get_struct()
- , get_info()
- , const_cast< png_color_16p >( &_info._background )
- );
- }
- if( _info._valid_histogram )
- {
- png_set_hIST( get_struct()
- , get_info()
- , const_cast< png_uint_16p >( &_info._histogram.front() )
- );
- }
- if( _info._valid_offset )
- {
- png_set_oFFs( get_struct()
- , get_info()
- , _info._offset_x
- , _info._offset_y
- , _info._off_unit_type
- );
- }
- if( _info._valid_pixel_calibration )
- {
- std::vector< const char* > params( _info._num_params );
- for( std::size_t i = 0; i < params.size(); ++i )
- {
- params[i] = _info._params[ i ].c_str();
- }
- png_set_pCAL( get_struct()
- , get_info()
- , const_cast< png_charp >( _info._purpose.c_str() )
- , _info._X0
- , _info._X1
- , _info._cal_type
- , _info._num_params
- , const_cast< png_charp >( _info._units.c_str() )
- , const_cast< png_charpp >( ¶ms.front() )
- );
- }
- if( _info._valid_resolution )
- {
- png_set_pHYs( get_struct()
- , get_info()
- , _info._res_x
- , _info._res_y
- , _info._phy_unit_type
- );
- }
- if( _info._valid_significant_bits )
- {
- png_set_sBIT( get_struct()
- , get_info()
- , const_cast< png_color_8p >( &_info._sig_bits )
- );
- }
- #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER
- #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
- if( _info._valid_scale_factors )
- {
- png_set_sCAL( get_struct()
- , get_info()
- , this->_info._scale_unit
- , this->_info._scale_width
- , this->_info._scale_height
- );
- }
- #else
- #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
- if( _info._valid_scale_factors )
- {
- png_set_sCAL_fixed( get_struct()
- , get_info()
- , this->_info._scale_unit
- , this->_info._scale_width
- , this->_info._scale_height
- );
- }
- #else
- if( _info._valid_scale_factors )
- {
- png_set_sCAL_s( get_struct()
- , get_info()
- , this->_info._scale_unit
- , const_cast< png_charp >( this->_info._scale_width.c_str() )
- , const_cast< png_charp >( this->_info._scale_height.c_str() )
- );
- }
- #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
- #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
- #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER
- if( _info._valid_text )
- {
- std::vector< png_text > texts( _info._num_text );
- for( std::size_t i = 0; i < texts.size(); ++i )
- {
- png_text pt;
- pt.compression = _info._text[i]._compression;
- pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() );
- pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() );
- pt.text_length = _info._text[i]._text.length();
- texts[i] = pt;
- }
- png_set_text( get_struct()
- , get_info()
- , &texts.front()
- , _info._num_text
- );
- }
- if( _info._valid_modification_time )
- {
- png_set_tIME( get_struct()
- , get_info()
- , const_cast< png_timep >( &_info._mod_time )
- );
- }
- if( _info._valid_transparency_factors )
- {
- int sample_max = ( 1u << _info._bit_depth );
- /* libpng doesn't reject a tRNS chunk with out-of-range samples */
- if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY
- && (int) _info._trans_values[0].gray > sample_max
- )
- || ( _info._color_type == PNG_COLOR_TYPE_RGB
- &&( (int) _info._trans_values[0].red > sample_max
- || (int) _info._trans_values[0].green > sample_max
- || (int) _info._trans_values[0].blue > sample_max
- )
- )
- )
- )
- {
- //@todo Fix that once reading transparency values works
- /*
- png_set_tRNS( get_struct()
- , get_info()
- , trans
- , num_trans
- , trans_values
- );
- */
- }
- }
- // Compression Levels - valid values are [0,9]
- png_set_compression_level( get_struct()
- , _info._compression_level
- );
- png_set_compression_mem_level( get_struct()
- , _info._compression_mem_level
- );
- png_set_compression_strategy( get_struct()
- , _info._compression_strategy
- );
- png_set_compression_window_bits( get_struct()
- , _info._compression_window_bits
- );
- png_set_compression_method( get_struct()
- , _info._compression_method
- );
- png_set_compression_buffer_size( get_struct()
- , _info._compression_buffer_size
- );
- #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
- // Dithering
- if( _info._set_dithering )
- {
- png_set_dither( get_struct()
- , &_info._dithering_palette.front()
- , _info._dithering_num_palette
- , _info._dithering_maximum_colors
- , &_info._dithering_histogram.front()
- , _info._full_dither
- );
- }
- #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
- // Filter
- if( _info._set_filter )
- {
- png_set_filter( get_struct()
- , 0
- , _info._filter
- );
- }
- // Invert Mono
- if( _info._invert_mono )
- {
- png_set_invert_mono( get_struct() );
- }
- // True Bits
- if( _info._set_true_bits )
- {
- png_set_sBIT( get_struct()
- , get_info()
- , &_info._true_bits.front()
- );
- }
- // sRGB Intent
- if( _info._set_srgb_intent )
- {
- png_set_sRGB( get_struct()
- , get_info()
- , _info._srgb_intent
- );
- }
- // Strip Alpha
- if( _info._strip_alpha )
- {
- png_set_strip_alpha( get_struct() );
- }
- // Swap Alpha
- if( _info._swap_alpha )
- {
- png_set_swap_alpha( get_struct() );
- }
- png_write_info( get_struct()
- , get_info()
- );
- }
- protected:
- static void write_data( png_structp png_ptr
- , png_bytep data
- , png_size_t length
- )
- {
- static_cast< Device* >( png_get_io_ptr( png_ptr ))->write( data
- , length );
- }
- static void flush( png_structp png_ptr )
- {
- static_cast< Device* >(png_get_io_ptr(png_ptr) )->flush();
- }
- private:
- void init_io( png_structp png_ptr )
- {
- png_set_write_fn( png_ptr
- , static_cast< void* > ( &this->_io_dev )
- , static_cast< png_rw_ptr > ( &this_t::write_data )
- , static_cast< png_flush_ptr >( &this_t::flush )
- );
- }
- public:
- Device _io_dev;
- image_write_info< png_tag > _info;
- };
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(pop)
- #endif
- } // namespace gil
- } // namespace boost
- #endif
|