Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:57

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_DETAIL_READER_BACKEND_HPP
0009 #define BOOST_GIL_EXTENSION_IO_DETAIL_READER_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 namespace boost { namespace gil {
0016 
0017 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0018 #pragma warning(push)
0019 #pragma warning(disable:4512) //assignment operator could not be generated
0020 #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
0021 #endif
0022 
0023 ///
0024 /// PNG Backend
0025 ///
0026 template<typename Device >
0027 struct reader_backend< Device
0028                      , png_tag
0029                      >
0030     : public detail::png_struct_info_wrapper
0031 {
0032 public:
0033 
0034     using format_tag_t = png_tag;
0035     using this_t = reader_backend<Device, png_tag>;
0036 
0037 public:
0038 
0039     reader_backend( const Device&                         io_dev
0040                   , const image_read_settings< png_tag >& settings
0041                   )
0042     : _io_dev( io_dev )
0043 
0044     , _settings( settings )
0045     , _info()
0046     , _scanline_length( 0 )
0047 
0048     , _number_passes( 0 )
0049     {
0050         read_header();
0051 
0052         if( _settings._dim.x == 0 )
0053         {
0054             _settings._dim.x = _info._width;
0055         }
0056 
0057         if( _settings._dim.y == 0 )
0058         {
0059             _settings._dim.y = _info._height;
0060         }
0061     }
0062 
0063     void read_header()
0064     {
0065         using boost::gil::detail::PNG_BYTES_TO_CHECK;
0066 
0067         // check the file's first few bytes
0068         byte_t buf[PNG_BYTES_TO_CHECK];
0069 
0070         io_error_if( _io_dev.read( buf
0071                                 , PNG_BYTES_TO_CHECK
0072                                 ) != PNG_BYTES_TO_CHECK
0073                    , "png_check_validity: failed to read image"
0074                    );
0075 
0076         io_error_if( png_sig_cmp( png_bytep(buf)
0077                                 , png_size_t(0)
0078                                 , PNG_BYTES_TO_CHECK
0079                                 ) != 0
0080                    , "png_check_validity: invalid png image"
0081                    );
0082 
0083         // Create and initialize the png_struct with the desired error handler
0084         // functions.  If you want to use the default stderr and longjump method,
0085         // you can supply NULL for the last three parameters.  We also supply the
0086         // the compiler header file version, so that we know if the application
0087         // was compiled with a compatible version of the library.  REQUIRED
0088         get()->_struct = png_create_read_struct( PNG_LIBPNG_VER_STRING
0089                                              , nullptr  // user_error_ptr
0090                                              , nullptr  // user_error_fn
0091                                              , nullptr  // user_warning_fn
0092                                              );
0093 
0094         io_error_if( get()->_struct == nullptr
0095                    , "png_reader: fail to call png_create_write_struct()"
0096                    );
0097 
0098         png_uint_32 user_chunk_data[4];
0099         user_chunk_data[0] = 0;
0100         user_chunk_data[1] = 0;
0101         user_chunk_data[2] = 0;
0102         user_chunk_data[3] = 0;
0103         png_set_read_user_chunk_fn( get_struct()
0104                                   , user_chunk_data
0105                                   , this_t::read_user_chunk_callback
0106                                   );
0107 
0108         // Allocate/initialize the memory for image information.  REQUIRED.
0109         get()->_info = png_create_info_struct( get_struct() );
0110 
0111         if( get_info() == nullptr )
0112         {
0113             png_destroy_read_struct( &get()->_struct
0114                                    , nullptr
0115                                    , nullptr
0116                                    );
0117 
0118             io_error( "png_reader: fail to call png_create_info_struct()" );
0119         }
0120 
0121         // Set error handling if you are using the setjmp/longjmp method (this is
0122         // the normal method of doing things with libpng).  REQUIRED unless you
0123         // set up your own error handlers in the png_create_read_struct() earlier.
0124         if( setjmp( png_jmpbuf( get_struct() )))
0125         {
0126             //free all of the memory associated with the png_ptr and info_ptr
0127             png_destroy_read_struct( &get()->_struct
0128                                    , &get()->_info
0129                                    , nullptr
0130                                    );
0131 
0132             io_error( "png is invalid" );
0133         }
0134 
0135         png_set_read_fn( get_struct()
0136                        , static_cast< png_voidp >( &this->_io_dev )
0137                        , this_t::read_data
0138                        );
0139 
0140         // Set up a callback function that will be
0141         // called after each row has been read, which you can use to control
0142         // a progress meter or the like.
0143         png_set_read_status_fn( get_struct()
0144                               , this_t::read_row_callback
0145                               );
0146 
0147         // Set up a callback which implements user defined transformation.
0148         // @todo
0149         png_set_read_user_transform_fn( get_struct()
0150                                       , png_user_transform_ptr( nullptr )
0151                                       );
0152 
0153         png_set_keep_unknown_chunks( get_struct()
0154                                    , PNG_HANDLE_CHUNK_ALWAYS
0155                                    , nullptr
0156                                    , 0
0157                                    );
0158 
0159 
0160         // Make sure we read the signature.
0161         // @todo make it an option
0162         png_set_sig_bytes( get_struct()
0163                          , PNG_BYTES_TO_CHECK
0164                          );
0165 
0166         // The call to png_read_info() gives us all of the information from the
0167         // PNG file before the first IDAT (image data chunk).  REQUIRED
0168         png_read_info( get_struct()
0169                      , get_info()
0170                      );
0171 
0172         ///
0173         /// Start reading the image information
0174         ///
0175 
0176         // get PNG_IHDR chunk information from png_info structure
0177         png_get_IHDR( get_struct()
0178                     , get_info()
0179                     , &this->_info._width
0180                     , &this->_info._height
0181                     , &this->_info._bit_depth
0182                     , &this->_info._color_type
0183                     , &this->_info._interlace_method
0184                     , &this->_info._compression_method
0185                     , &this->_info._filter_method
0186                     );
0187 
0188         // get number of color channels in image
0189         this->_info._num_channels = png_get_channels( get_struct()
0190                                               , get_info()
0191                                               );
0192 
0193 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0194 
0195         // Get CIE chromacities and referenced white point
0196         if( this->_settings._read_cie_chromacities )
0197         {
0198             this->_info._valid_cie_colors = png_get_cHRM( get_struct()
0199                                                         , get_info()
0200                                                         , &this->_info._white_x, &this->_info._white_y
0201                                                         ,   &this->_info._red_x,   &this->_info._red_y
0202                                                         , &this->_info._green_x, &this->_info._green_y
0203                                                         ,  &this->_info._blue_x,  &this->_info._blue_y
0204                                                         );
0205         }
0206 
0207         // get the gamma value
0208         if( this->_settings._read_file_gamma )
0209         {
0210             this->_info._valid_file_gamma = png_get_gAMA( get_struct()
0211                                                         , get_info()
0212                                                         , &this->_info._file_gamma
0213                                                         );
0214 
0215             if( this->_info._valid_file_gamma == false )
0216             {
0217                 this->_info._file_gamma = 1.0;
0218             }
0219         }
0220 #else
0221 
0222         // Get CIE chromacities and referenced white point
0223         if( this->_settings._read_cie_chromacities )
0224         {
0225             this->_info._valid_cie_colors = png_get_cHRM_fixed( get_struct()
0226                                                               , get_info()
0227                                                               , &this->_info._white_x, &this->_info._white_y
0228                                                               ,   &this->_info._red_x,   &this->_info._red_y
0229                                                               , &this->_info._green_x, &this->_info._green_y
0230                                                               ,  &this->_info._blue_x,  &this->_info._blue_y
0231                                                               );
0232         }
0233 
0234         // get the gamma value
0235         if( this->_settings._read_file_gamma )
0236         {
0237             this->_info._valid_file_gamma = png_get_gAMA_fixed( get_struct()
0238                                                               , get_info()
0239                                                               , &this->_info._file_gamma
0240                                                               );
0241 
0242             if( this->_info._valid_file_gamma == false )
0243             {
0244                 this->_info._file_gamma = 1;
0245             }
0246         }
0247 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0248 
0249         // get the embedded ICC profile data
0250         if( this->_settings._read_icc_profile )
0251         {
0252 #if PNG_LIBPNG_VER_MINOR >= 5
0253             png_charp icc_name = png_charp( nullptr );
0254             png_bytep profile  = png_bytep( nullptr );
0255 
0256             this->_info._valid_icc_profile = png_get_iCCP( get_struct()
0257                                                          , get_info()
0258                                                          , &icc_name
0259                                                          , &this->_info._iccp_compression_type
0260                                                          , &profile
0261                                                          , &this->_info._profile_length
0262                                                          );
0263 #else
0264             png_charp icc_name = png_charp( NULL );
0265             png_charp profile  = png_charp( NULL );
0266 
0267             this->_info._valid_icc_profile = png_get_iCCP( get_struct()
0268                                                          , get_info()
0269                                                          , &icc_name
0270                                                          , &this->_info._iccp_compression_type
0271                                                          , &profile
0272                                                          , &this->_info._profile_length
0273                                                          );
0274 #endif
0275             if( icc_name )
0276             {
0277                 this->_info._icc_name.append( icc_name
0278                                             , std::strlen( icc_name )
0279                                             );
0280             }
0281 
0282             if( this->_info._profile_length != 0 )
0283             {
0284                 std:: copy_n (profile, this->_info._profile_length, std:: back_inserter (this->_info._profile));
0285             }
0286         }
0287 
0288         // get the rendering intent
0289         if( this->_settings._read_intent )
0290         {
0291             this->_info._valid_intent = png_get_sRGB( get_struct()
0292                                                     , get_info()
0293                                                     , &this->_info._intent
0294                                                     );
0295         }
0296 
0297         // get image palette information from png_info structure
0298         if( this->_settings._read_palette )
0299         {
0300             png_colorp palette = png_colorp( nullptr );
0301 
0302             this->_info._valid_palette = png_get_PLTE( get_struct()
0303                                                      , get_info()
0304                                                      , &palette
0305                                                      , &this->_info._num_palette
0306                                                      );
0307 
0308             if( this->_info._num_palette > 0 )
0309             {
0310                 this->_info._palette.resize( this->_info._num_palette );
0311                 std::copy( palette
0312                          , palette + this->_info._num_palette
0313                          , &this->_info._palette.front()
0314                          );
0315             }
0316         }
0317 
0318         // get background color
0319         if( this->_settings._read_background )
0320         {
0321             png_color_16p background = png_color_16p( nullptr );
0322 
0323             this->_info._valid_background = png_get_bKGD( get_struct()
0324                                                         , get_info()
0325                                                         , &background
0326                                                         );
0327             if( background )
0328             {
0329                 this->_info._background = *background;
0330             }
0331         }
0332 
0333         // get the histogram
0334         if( this->_settings._read_histogram )
0335         {
0336             png_uint_16p histogram = png_uint_16p( nullptr );
0337 
0338             this->_info._valid_histogram = png_get_hIST( get_struct()
0339                                                        , get_info()
0340                                                        , &histogram
0341                                                        );
0342 
0343             if( histogram )
0344             {
0345                 // the number of values is set by the number of colors inside
0346                 // the palette.
0347                 if( this->_settings._read_palette == false )
0348                 {
0349                     png_colorp palette = png_colorp( nullptr );
0350                     png_get_PLTE( get_struct()
0351                                 , get_info()
0352                                 , &palette
0353                                 , &this->_info._num_palette
0354                                 );
0355                 }
0356 
0357                 std::copy( histogram
0358                          , histogram + this->_info._num_palette
0359                          , &this->_info._histogram.front()
0360                          );
0361             }
0362         }
0363 
0364         // get screen offsets for the given image
0365         if( this->_settings._read_screen_offsets )
0366         {
0367             this->_info._valid_offset = png_get_oFFs( get_struct()
0368                                                     , get_info()
0369                                                     , &this->_info._offset_x
0370                                                     , &this->_info._offset_y
0371                                                     , &this->_info._off_unit_type
0372                                                     );
0373         }
0374 
0375 
0376         // get pixel calibration settings
0377         if( this->_settings._read_pixel_calibration )
0378         {
0379             png_charp purpose = png_charp ( nullptr );
0380             png_charp units   = png_charp ( nullptr );
0381             png_charpp params = png_charpp( nullptr );
0382 
0383             this->_info._valid_pixel_calibration = png_get_pCAL( get_struct()
0384                                                                , get_info()
0385                                                                , &purpose
0386                                                                , &this->_info._X0
0387                                                                , &this->_info._X1
0388                                                                , &this->_info._cal_type
0389                                                                , &this->_info._num_params
0390                                                                , &units
0391                                                                , &params
0392                                                                );
0393             if( purpose )
0394             {
0395                 this->_info._purpose.append( purpose
0396                                            , std::strlen( purpose )
0397                                            );
0398             }
0399 
0400             if( units )
0401             {
0402                 this->_info._units.append( units
0403                                          , std::strlen( units )
0404                                          );
0405             }
0406 
0407             if( this->_info._num_params > 0 )
0408             {
0409                 this->_info._params.resize( this->_info._num_params );
0410 
0411                 for( png_CAL_nparam::type i = 0
0412                    ; i < this->_info._num_params
0413                    ; ++i
0414                    )
0415                 {
0416                     this->_info._params[i].append( params[i]
0417                                                  , std::strlen( params[i] )
0418                                                  );
0419                 }
0420             }
0421         }
0422 
0423         // get the physical resolution
0424         if( this->_settings._read_physical_resolution )
0425         {
0426             this->_info._valid_resolution = png_get_pHYs( get_struct()
0427                                                         , get_info()
0428                                                         , &this->_info._res_x
0429                                                         , &this->_info._res_y
0430                                                         , &this->_info._phy_unit_type
0431                                                         );
0432         }
0433 
0434         // get the image resolution in pixels per meter.
0435         if( this->_settings._read_pixels_per_meter )
0436         {
0437             this->_info._pixels_per_meter = png_get_pixels_per_meter( get_struct()
0438                                                                     , get_info()
0439                                                                     );
0440         }
0441 
0442 
0443         // get number of significant bits for each color channel
0444         if( this->_settings._read_number_of_significant_bits )
0445         {
0446             png_color_8p sig_bits = png_color_8p( nullptr );
0447 
0448             this->_info._valid_significant_bits = png_get_sBIT( get_struct()
0449                                                               , get_info()
0450                                                               , &sig_bits
0451                                                               );
0452 
0453             // @todo Is there one or more colors?
0454             if( sig_bits )
0455             {
0456                 this->_info._sig_bits = *sig_bits;
0457             }
0458         }
0459 
0460 #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER
0461 
0462 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0463 
0464         // get physical scale settings
0465         if( this->_settings._read_scale_factors )
0466         {
0467             this->_info._valid_scale_factors = png_get_sCAL( get_struct()
0468                                                            , get_info()
0469                                                            , &this->_info._scale_unit
0470                                                            , &this->_info._scale_width
0471                                                            , &this->_info._scale_height
0472                                                            );
0473         }
0474 #else
0475 #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
0476         if( this->_settings._read_scale_factors )
0477         {
0478             this->_info._valid_scale_factors = png_get_sCAL_fixed( get_struct()
0479                                                                  , get_info()
0480                                                                  , &this->_info._scale_unit
0481                                                                  , &this->_info._scale_width
0482                                                                  , &this->_info._scale_height
0483                                                                  );
0484         }
0485 #else
0486         if( this->_settings._read_scale_factors )
0487         {
0488             png_charp scale_width  = nullptr;
0489             png_charp scale_height = nullptr;
0490 
0491             this->_info._valid_scale_factors = png_get_sCAL_s(
0492                 get_struct(), get_info(), &this->_info._scale_unit, &scale_width, &scale_height);
0493 
0494             if (this->_info._valid_scale_factors)
0495             {
0496                 if( scale_width )
0497                 {
0498                     this->_info._scale_width.append( scale_width
0499                                                    , std::strlen( scale_width )
0500                                                    );
0501                 }
0502 
0503                 if( scale_height )
0504                 {
0505                     this->_info._scale_height.append( scale_height
0506                                                     , std::strlen( scale_height )
0507                                                     );
0508                 }
0509             }
0510         }
0511 #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
0512 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0513 #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER
0514 
0515         // get comments information from png_info structure
0516         if( this->_settings._read_comments )
0517         {
0518             png_textp text = png_textp( nullptr );
0519 
0520             this->_info._valid_text = png_get_text( get_struct()
0521                                                   , get_info()
0522                                                   , &text
0523                                                   , &this->_info._num_text
0524                                                   );
0525 
0526             if( this->_info._num_text > 0 )
0527             {
0528                 this->_info._text.resize( this->_info._num_text );
0529 
0530                 for( png_num_text::type i = 0
0531                    ; i < this->_info._num_text
0532                    ; ++i
0533                    )
0534                 {
0535                     this->_info._text[i]._compression = text[i].compression;
0536                     this->_info._text[i]._key.append( text[i].key
0537                                                     , std::strlen( text[i].key )
0538                                                     );
0539 
0540                     this->_info._text[i]._text.append( text[i].text
0541                                                      , std::strlen( text[i].text )
0542                                                      );
0543                 }
0544             }
0545         }
0546 
0547         // get last modification time
0548         if( this->_settings._read_last_modification_time )
0549         {
0550             png_timep mod_time = png_timep( nullptr );
0551             this->_info._valid_modification_time = png_get_tIME( get_struct()
0552                                                                , get_info()
0553                                                                , &mod_time
0554                                                                );
0555             if( mod_time )
0556             {
0557                 this->_info._mod_time = *mod_time;
0558             }
0559         }
0560 
0561         // get transparency data
0562         if( this->_settings._read_transparency_data )
0563         {
0564             png_bytep     trans        = png_bytep    ( nullptr );
0565             png_color_16p trans_values = png_color_16p( nullptr );
0566 
0567             this->_info._valid_transparency_factors = png_get_tRNS( get_struct()
0568                                                                   , get_info()
0569                                                                   , &trans
0570                                                                   , &this->_info._num_trans
0571                                                                   , &trans_values
0572                                                                   );
0573 
0574             if( trans )
0575             {
0576                 //@todo What to do, here? How do I know the length of the "trans" array?
0577             }
0578 
0579             if( this->_info._num_trans )
0580             {
0581                 this->_info._trans_values.resize( this->_info._num_trans );
0582                 std::copy( trans_values
0583                          , trans_values + this->_info._num_trans
0584                          , &this->_info._trans_values.front()
0585                          );
0586             }
0587         }
0588 
0589         // @todo One day!
0590 /*
0591         if( false )
0592         {
0593             png_unknown_chunkp unknowns = png_unknown_chunkp( NULL );
0594             int num_unknowns = static_cast< int >( png_get_unknown_chunks( get_struct()
0595                                                                          , get_info()
0596                                                                          , &unknowns
0597                                                                          )
0598                                                  );
0599         }
0600 */
0601     }
0602 
0603     /// Check if image is large enough.
0604     void check_image_size( point_t const& img_dim )
0605     {
0606         if( _settings._dim.x > 0 )
0607         {
0608             if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
0609         }
0610         else
0611         {
0612             if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
0613         }
0614 
0615 
0616         if( _settings._dim.y > 0 )
0617         {
0618             if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
0619         }
0620         else
0621         {
0622             if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
0623         }
0624     }
0625 
0626 protected:
0627 
0628     static void read_data( png_structp png_ptr
0629                          , png_bytep   data
0630                          , png_size_t length
0631                          )
0632     {
0633         static_cast<Device*>(png_get_io_ptr(png_ptr) )->read( data
0634                                                             , length );
0635     }
0636 
0637     static void flush( png_structp png_ptr )
0638     {
0639         static_cast<Device*>(png_get_io_ptr(png_ptr) )->flush();
0640     }
0641 
0642 
0643     static int read_user_chunk_callback( png_struct*        /* png_ptr */
0644                                        , png_unknown_chunkp /* chunk */
0645                                        )
0646     {
0647         // @todo
0648         return 0;
0649     }
0650 
0651     static void read_row_callback( png_structp /* png_ptr    */
0652                                  , png_uint_32 /* row_number */
0653                                  , int         /* pass       */
0654                                  )
0655     {
0656         // @todo
0657     }
0658 
0659 public:
0660 
0661     Device _io_dev;
0662 
0663     image_read_settings< png_tag > _settings;
0664     image_read_info    < png_tag > _info;
0665 
0666     std::size_t _scanline_length;
0667 
0668     std::size_t _number_passes;
0669 };
0670 
0671 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0672 #pragma warning(pop)
0673 #endif
0674 
0675 } // namespace gil
0676 } // namespace boost
0677 
0678 #endif