Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:12:30

0001 //
0002 // Copyright 2012 Christian Henning
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
0010 
0011 #include <boost/gil/extension/io/png/tags.hpp>
0012 #include <boost/gil/extension/io/png/detail/base.hpp>
0013 #include <boost/gil/extension/io/png/detail/supported_types.hpp>
0014 
0015 #include <boost/gil/io/base.hpp>
0016 #include <boost/gil/io/typedefs.hpp>
0017 
0018 namespace boost { namespace gil {
0019 
0020 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0021 #pragma warning(push)
0022 #pragma warning(disable:4512) //assignment operator could not be generated
0023 #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
0024 #endif
0025 
0026 ///
0027 /// PNG Writer Backend
0028 ///
0029 template< typename Device >
0030 struct writer_backend< Device
0031                      , png_tag
0032                      >
0033     : public detail::png_struct_info_wrapper
0034 {
0035 
0036 private:
0037 
0038     using this_t = writer_backend<Device, png_tag>;
0039 
0040 public:
0041 
0042     using format_tag_t = png_tag;
0043 
0044     ///
0045     /// Constructor
0046     ///
0047     writer_backend( const Device&                      io_dev
0048                   , const image_write_info< png_tag >& info
0049                   )
0050     : png_struct_info_wrapper( false )
0051     , _io_dev( io_dev )
0052     , _info( info )
0053     {
0054         // Create and initialize the png_struct with the desired error handler
0055         // functions.  If you want to use the default stderr and longjump method,
0056         // you can supply NULL for the last three parameters.  We also check that
0057         // the library version is compatible with the one used at compile time,
0058         // in case we are using dynamically linked libraries.  REQUIRED.
0059         get()->_struct = png_create_write_struct( PNG_LIBPNG_VER_STRING
0060                                                 , nullptr  // user_error_ptr
0061                                                 , nullptr  // user_error_fn
0062                                                 , nullptr  // user_warning_fn
0063                                                 );
0064 
0065         io_error_if( get_struct() == nullptr
0066                    , "png_writer: fail to call png_create_write_struct()"
0067                    );
0068 
0069         // Allocate/initialize the image information data.  REQUIRED
0070         get()->_info = png_create_info_struct( get_struct() );
0071 
0072         if( get_info() == nullptr )
0073         {
0074             png_destroy_write_struct( &get()->_struct
0075                                     , nullptr
0076                                     );
0077 
0078             io_error( "png_writer: fail to call png_create_info_struct()" );
0079         }
0080 
0081         // Set error handling.  REQUIRED if you aren't supplying your own
0082         // error handling functions in the png_create_write_struct() call.
0083         if( setjmp( png_jmpbuf( get_struct() )))
0084         {
0085             //free all of the memory associated with the png_ptr and info_ptr
0086             png_destroy_write_struct( &get()->_struct
0087                                     , &get()->_info
0088                                     );
0089 
0090             io_error( "png_writer: fail to call setjmp()" );
0091         }
0092 
0093         init_io( get_struct() );
0094     }
0095 
0096 protected:
0097 
0098     template< typename View >
0099     void write_header( const View& view )
0100     {
0101         using png_rw_info_t = detail::png_write_support
0102             <
0103                 typename channel_type<typename get_pixel_type<View>::type>::type,
0104                 typename color_space_type<View>::type
0105             >;
0106 
0107         // Set the image information here.  Width and height are up to 2^31,
0108         // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
0109         // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
0110         // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
0111         // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
0112         // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
0113         // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
0114         png_set_IHDR( get_struct()
0115                     , get_info()
0116                     , static_cast< png_image_width::type  >( view.width()  )
0117                     , static_cast< png_image_height::type >( view.height() )
0118                     , static_cast< png_bitdepth::type     >( png_rw_info_t::_bit_depth )
0119                     , static_cast< png_color_type::type   >( png_rw_info_t::_color_type )
0120                     , _info._interlace_method
0121                     , _info._compression_type
0122                     , _info._filter_method
0123                     );
0124 
0125 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0126         if( _info._valid_cie_colors )
0127         {
0128             png_set_cHRM( get_struct()
0129                         , get_info()
0130                         , _info._white_x
0131                         , _info._white_y
0132                         , _info._red_x
0133                         , _info._red_y
0134                         , _info._green_x
0135                         , _info._green_y
0136                         , _info._blue_x
0137                         , _info._blue_y
0138                         );
0139         }
0140 
0141         if( _info._valid_file_gamma )
0142         {
0143             png_set_gAMA( get_struct()
0144                         , get_info()
0145                         , _info._file_gamma
0146                         );
0147         }
0148 #else
0149         if( _info._valid_cie_colors )
0150         {
0151             png_set_cHRM_fixed( get_struct()
0152                               , get_info()
0153                               , _info._white_x
0154                               , _info._white_y
0155                               , _info._red_x
0156                               , _info._red_y
0157                               , _info._green_x
0158                               , _info._green_y
0159                               , _info._blue_x
0160                               , _info._blue_y
0161                               );
0162         }
0163 
0164         if( _info._valid_file_gamma )
0165         {
0166             png_set_gAMA_fixed( get_struct()
0167                               , get_info()
0168                               , _info._file_gamma
0169                               );
0170         }
0171 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0172 
0173         if( _info._valid_icc_profile )
0174         {
0175 #if PNG_LIBPNG_VER_MINOR >= 5
0176             png_set_iCCP( get_struct()
0177                         , get_info()
0178                         , const_cast< png_charp >( _info._icc_name.c_str() )
0179                         , _info._iccp_compression_type
0180                         , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) )
0181                         , _info._profile_length
0182                         );
0183 #else
0184             png_set_iCCP( get_struct()
0185                         , get_info()
0186                         , const_cast< png_charp >( _info._icc_name.c_str() )
0187                         , _info._iccp_compression_type
0188                         , const_cast< png_charp >( & (_info._profile.front()) )
0189                         , _info._profile_length
0190                         );
0191 #endif
0192         }
0193 
0194         if( _info._valid_intent )
0195         {
0196             png_set_sRGB( get_struct()
0197                         , get_info()
0198                         , _info._intent
0199                         );
0200         }
0201 
0202         if( _info._valid_palette )
0203         {
0204             png_set_PLTE( get_struct()
0205                         , get_info()
0206                         , const_cast< png_colorp >( &_info._palette.front() )
0207                         , _info._num_palette
0208                         );
0209         }
0210 
0211         if( _info._valid_background )
0212         {
0213             png_set_bKGD( get_struct()
0214                         , get_info()
0215                         , const_cast< png_color_16p >( &_info._background )
0216                         );
0217         }
0218 
0219         if( _info._valid_histogram )
0220         {
0221             png_set_hIST( get_struct()
0222                         , get_info()
0223                         , const_cast< png_uint_16p >( &_info._histogram.front() )
0224                         );
0225         }
0226 
0227         if( _info._valid_offset )
0228         {
0229             png_set_oFFs( get_struct()
0230                         , get_info()
0231                         , _info._offset_x
0232                         , _info._offset_y
0233                         , _info._off_unit_type
0234                         );
0235         }
0236 
0237         if( _info._valid_pixel_calibration )
0238         {
0239             std::vector< const char* > params( _info._num_params );
0240             for( std::size_t i = 0; i < params.size(); ++i )
0241             {
0242                 params[i] = _info._params[ i ].c_str();
0243             }
0244 
0245             png_set_pCAL( get_struct()
0246                         , get_info()
0247                         , const_cast< png_charp >( _info._purpose.c_str() )
0248                         , _info._X0
0249                         , _info._X1
0250                         , _info._cal_type
0251                         , _info._num_params
0252                         , const_cast< png_charp  >( _info._units.c_str() )
0253                         , const_cast< png_charpp >( &params.front()     )
0254                         );
0255         }
0256 
0257         if( _info._valid_resolution )
0258         {
0259             png_set_pHYs( get_struct()
0260                         , get_info()
0261                         , _info._res_x
0262                         , _info._res_y
0263                         , _info._phy_unit_type
0264                         );
0265         }
0266 
0267         if( _info._valid_significant_bits )
0268         {
0269             png_set_sBIT( get_struct()
0270                         , get_info()
0271                         , const_cast< png_color_8p >( &_info._sig_bits )
0272                         );
0273         }
0274 
0275 #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER
0276 
0277 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0278         if( _info._valid_scale_factors )
0279         {
0280             png_set_sCAL( get_struct()
0281                         , get_info()
0282                         , this->_info._scale_unit
0283                         , this->_info._scale_width
0284                         , this->_info._scale_height
0285                         );
0286         }
0287 #else
0288 #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
0289         if( _info._valid_scale_factors )
0290         {
0291             png_set_sCAL_fixed( get_struct()
0292                               , get_info()
0293                               , this->_info._scale_unit
0294                               , this->_info._scale_width
0295                               , this->_info._scale_height
0296                               );
0297         }
0298 #else
0299         if( _info._valid_scale_factors )
0300         {
0301             png_set_sCAL_s( get_struct()
0302                           , get_info()
0303                           , this->_info._scale_unit
0304                           , const_cast< png_charp >( this->_info._scale_width.c_str()  )
0305                           , const_cast< png_charp >( this->_info._scale_height.c_str() )
0306                           );
0307         }
0308 
0309 #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
0310 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0311 #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER
0312 
0313         if( _info._valid_text )
0314         {
0315             std::vector< png_text > texts( _info._num_text );
0316             for( std::size_t i = 0; i < texts.size(); ++i )
0317             {
0318                 png_text pt;
0319                 pt.compression = _info._text[i]._compression;
0320                 pt.key         = const_cast< png_charp >( this->_info._text[i]._key.c_str()  );
0321                 pt.text        = const_cast< png_charp >( this->_info._text[i]._text.c_str() );
0322                 pt.text_length = _info._text[i]._text.length();
0323 
0324                 texts[i] = pt;
0325             }
0326 
0327             png_set_text( get_struct()
0328                         , get_info()
0329                         , &texts.front()
0330                         , _info._num_text
0331                         );
0332         }
0333 
0334         if( _info._valid_modification_time )
0335         {
0336             png_set_tIME( get_struct()
0337                         , get_info()
0338                         , const_cast< png_timep >( &_info._mod_time )
0339                         );
0340         }
0341 
0342         if( _info._valid_transparency_factors )
0343         {
0344             int sample_max = ( 1u << _info._bit_depth );
0345 
0346             /* libpng doesn't reject a tRNS chunk with out-of-range samples */
0347             if( !(  (  _info._color_type == PNG_COLOR_TYPE_GRAY
0348                     && (int) _info._trans_values[0].gray > sample_max
0349                     )
0350                  || (  _info._color_type == PNG_COLOR_TYPE_RGB
0351                     &&(  (int) _info._trans_values[0].red   > sample_max
0352                       || (int) _info._trans_values[0].green > sample_max
0353                       || (int) _info._trans_values[0].blue  > sample_max
0354                       )
0355                     )
0356                  )
0357               )
0358             {
0359                 //@todo Fix that once reading transparency values works
0360 /*
0361                 png_set_tRNS( get_struct()
0362                             , get_info()
0363                             , trans
0364                             , num_trans
0365                             , trans_values
0366                             );
0367 */
0368             }
0369         }
0370 
0371         // Compression Levels - valid values are [0,9]
0372         png_set_compression_level( get_struct()
0373                                  , _info._compression_level
0374                                  );
0375 
0376         png_set_compression_mem_level( get_struct()
0377                                      , _info._compression_mem_level
0378                                      );
0379 
0380         png_set_compression_strategy( get_struct()
0381                                     , _info._compression_strategy
0382                                     );
0383 
0384         png_set_compression_window_bits( get_struct()
0385                                        , _info._compression_window_bits
0386                                        );
0387 
0388         png_set_compression_method( get_struct()
0389                                   , _info._compression_method
0390                                   );
0391 
0392         png_set_compression_buffer_size( get_struct()
0393                                        , _info._compression_buffer_size
0394                                        );
0395 
0396 #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
0397         // Dithering
0398         if( _info._set_dithering )
0399         {
0400             png_set_dither( get_struct()
0401                           , &_info._dithering_palette.front()
0402                           , _info._dithering_num_palette
0403                           , _info._dithering_maximum_colors
0404                           , &_info._dithering_histogram.front()
0405                           , _info._full_dither
0406                           );
0407         }
0408 #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
0409 
0410         // Filter
0411         if( _info._set_filter )
0412         {
0413             png_set_filter( get_struct()
0414                           , 0
0415                           , _info._filter
0416                           );
0417         }
0418 
0419         // Invert Mono
0420         if( _info._invert_mono )
0421         {
0422             png_set_invert_mono( get_struct() );
0423         }
0424 
0425         // True Bits
0426         if( _info._set_true_bits )
0427         {
0428             png_set_sBIT( get_struct()
0429                         , get_info()
0430                         , &_info._true_bits.front()
0431                         );
0432         }
0433 
0434         // sRGB Intent
0435         if( _info._set_srgb_intent )
0436         {
0437             png_set_sRGB( get_struct()
0438                         , get_info()
0439                         , _info._srgb_intent
0440                         );
0441         }
0442 
0443         // Strip Alpha
0444         if( _info._strip_alpha )
0445         {
0446             png_set_strip_alpha( get_struct() );
0447         }
0448 
0449         // Swap Alpha
0450         if( _info._swap_alpha )
0451         {
0452             png_set_swap_alpha( get_struct() );
0453         }
0454 
0455 
0456         png_write_info( get_struct()
0457                       , get_info()
0458                       );
0459     }
0460 
0461 protected:
0462 
0463     static void write_data( png_structp png_ptr
0464                           , png_bytep   data
0465                           , png_size_t  length
0466                           )
0467     {
0468         static_cast< Device* >( png_get_io_ptr( png_ptr ))->write( data
0469                                                                  , length );
0470     }
0471 
0472     static void flush( png_structp png_ptr )
0473     {
0474         static_cast< Device* >(png_get_io_ptr(png_ptr) )->flush();
0475     }
0476 
0477 private:
0478 
0479     void init_io( png_structp png_ptr )
0480     {
0481         png_set_write_fn( png_ptr
0482                         , static_cast< void* >        ( &this->_io_dev      )
0483                         , static_cast< png_rw_ptr >   ( &this_t::write_data )
0484                         , static_cast< png_flush_ptr >( &this_t::flush      )
0485                         );
0486     }
0487 
0488 public:
0489 
0490     Device _io_dev;
0491 
0492     image_write_info< png_tag > _info;
0493 };
0494 
0495 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0496 #pragma warning(pop)
0497 #endif
0498 
0499 } // namespace gil
0500 } // namespace boost
0501 
0502 #endif