File indexing completed on 2025-01-18 09:36:57
0001
0002
0003
0004
0005
0006
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)
0020 #pragma warning(disable:4611)
0021 #endif
0022
0023
0024
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
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
0084
0085
0086
0087
0088 get()->_struct = png_create_read_struct( PNG_LIBPNG_VER_STRING
0089 , nullptr
0090 , nullptr
0091 , nullptr
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
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
0122
0123
0124 if( setjmp( png_jmpbuf( get_struct() )))
0125 {
0126
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
0141
0142
0143 png_set_read_status_fn( get_struct()
0144 , this_t::read_row_callback
0145 );
0146
0147
0148
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
0161
0162 png_set_sig_bytes( get_struct()
0163 , PNG_BYTES_TO_CHECK
0164 );
0165
0166
0167
0168 png_read_info( get_struct()
0169 , get_info()
0170 );
0171
0172
0173
0174
0175
0176
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
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
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
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
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
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
0248
0249
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
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
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
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
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
0346
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
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
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 , ¶ms
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
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
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
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
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
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
0512 #endif
0513 #endif
0514
0515
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
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
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
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
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601 }
0602
0603
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*
0644 , png_unknown_chunkp
0645 )
0646 {
0647
0648 return 0;
0649 }
0650
0651 static void read_row_callback( png_structp
0652 , png_uint_32
0653 , int
0654 )
0655 {
0656
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 }
0676 }
0677
0678 #endif