File indexing completed on 2025-01-18 09:36:57
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
0010
0011 #include <boost/gil/extension/io/png/tags.hpp>
0012 #include <boost/gil/extension/io/png/detail/reader_backend.hpp>
0013 #include <boost/gil/extension/io/png/detail/is_allowed.hpp>
0014
0015 #include <boost/gil.hpp> // FIXME: Include what you use!
0016 #include <boost/gil/io/detail/dynamic.hpp>
0017 #include <boost/gil/io/base.hpp>
0018 #include <boost/gil/io/conversion_policies.hpp>
0019 #include <boost/gil/io/device.hpp>
0020 #include <boost/gil/io/error.hpp>
0021 #include <boost/gil/io/reader_base.hpp>
0022 #include <boost/gil/io/row_buffer_helper.hpp>
0023 #include <boost/gil/io/typedefs.hpp>
0024
0025 #include <type_traits>
0026
0027 namespace boost { namespace gil {
0028
0029 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0030 #pragma warning(push)
0031 #pragma warning(disable:4512)
0032 #endif
0033
0034
0035
0036
0037 template< typename Device
0038 , typename ConversionPolicy
0039 >
0040 class reader< Device
0041 , png_tag
0042 , ConversionPolicy
0043 >
0044 : public reader_base< png_tag
0045 , ConversionPolicy >
0046 , public reader_backend< Device
0047 , png_tag
0048 >
0049 {
0050 private:
0051
0052 using this_t = reader<Device, png_tag, ConversionPolicy>;
0053 using cc_t = typename ConversionPolicy::color_converter_type;
0054
0055 public:
0056
0057 using backend_t = reader_backend<Device, png_tag>;
0058
0059 public:
0060
0061 reader( const Device& io_dev
0062 , const image_read_settings< png_tag >& settings
0063 )
0064 : reader_base< png_tag
0065 , ConversionPolicy
0066 >()
0067 , backend_t( io_dev
0068 , settings
0069 )
0070 {}
0071
0072 reader( const Device& io_dev
0073 , const typename ConversionPolicy::color_converter_type& cc
0074 , const image_read_settings< png_tag >& settings
0075 )
0076 : reader_base< png_tag
0077 , ConversionPolicy
0078 >( cc )
0079 , backend_t( io_dev
0080 , settings
0081 )
0082 {}
0083
0084 template< typename View >
0085 void apply( const View& view )
0086 {
0087
0088 if (setjmp( png_jmpbuf( this->get_struct() )))
0089 {
0090 io_error("png is invalid");
0091 }
0092
0093
0094
0095
0096
0097 if( little_endian() )
0098 {
0099 if( this->_info._bit_depth == 16 )
0100 {
0101
0102 png_set_swap( this->get_struct() );
0103 }
0104
0105 if( this->_info._bit_depth < 8 )
0106 {
0107
0108 png_set_packswap( this->get_struct() );
0109 }
0110 }
0111
0112 if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE )
0113 {
0114 png_set_palette_to_rgb( this->get_struct() );
0115 }
0116
0117 if( png_get_valid( this->get_struct(), this->get_info(), PNG_INFO_tRNS ) )
0118 {
0119 png_set_tRNS_to_alpha( this->get_struct() );
0120 }
0121
0122
0123
0124
0125
0126 if( this->_settings._apply_screen_gamma )
0127 {
0128
0129
0130 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0131 png_set_gamma( this->get_struct()
0132 , this->_settings._screen_gamma
0133 , this->_info._file_gamma
0134 );
0135 #else
0136 png_set_gamma( this->get_struct()
0137 , this->_settings._screen_gamma
0138 , this->_info._file_gamma
0139 );
0140 #endif
0141 }
0142
0143
0144
0145
0146 this->_number_passes = png_set_interlace_handling( this->get_struct() );
0147
0148
0149
0150 png_read_update_info( this->get_struct()
0151 , this->get_info()
0152 );
0153
0154 this->_info._bit_depth = png_get_bit_depth( this->get_struct()
0155 , this->get_info()
0156 );
0157
0158 this->_info._num_channels = png_get_channels( this->get_struct()
0159 , this->get_info()
0160 );
0161
0162 this->_info._color_type = png_get_color_type( this->get_struct()
0163 , this->get_info()
0164 );
0165
0166 this->_scanline_length = png_get_rowbytes( this->get_struct()
0167 , this->get_info()
0168 );
0169
0170 switch( this->_info._color_type )
0171 {
0172 case PNG_COLOR_TYPE_GRAY:
0173 {
0174 switch( this->_info._bit_depth )
0175 {
0176 case 1: read_rows< gray1_image_t::view_t::reference >( view ); break;
0177 case 2: read_rows< gray2_image_t::view_t::reference >( view ); break;
0178 case 4: read_rows< gray4_image_t::view_t::reference >( view ); break;
0179 case 8: read_rows< gray8_pixel_t >( view ); break;
0180 case 16: read_rows< gray16_pixel_t >( view ); break;
0181 default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
0182 }
0183
0184 break;
0185 }
0186 case PNG_COLOR_TYPE_GA:
0187 {
0188 #ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA
0189 switch( this->_info._bit_depth )
0190 {
0191 case 8: read_rows< gray_alpha8_pixel_t > ( view ); break;
0192 case 16: read_rows< gray_alpha16_pixel_t >( view ); break;
0193 default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
0194 }
0195 #else
0196 io_error( "gray_alpha isn't enabled. Define BOOST_GIL_IO_ENABLE_GRAY_ALPHA when building application." );
0197 #endif
0198
0199
0200 break;
0201 }
0202 case PNG_COLOR_TYPE_RGB:
0203 {
0204 switch( this->_info._bit_depth )
0205 {
0206 case 8: read_rows< rgb8_pixel_t > ( view ); break;
0207 case 16: read_rows< rgb16_pixel_t >( view ); break;
0208 default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
0209 }
0210
0211 break;
0212 }
0213 case PNG_COLOR_TYPE_RGBA:
0214 {
0215 switch( this->_info._bit_depth )
0216 {
0217 case 8: read_rows< rgba8_pixel_t > ( view ); break;
0218 case 16: read_rows< rgba16_pixel_t >( view ); break;
0219 default: io_error( "png_reader_color_convert::read_data(): unknown combination of color type and bit depth" );
0220 }
0221
0222 break;
0223 }
0224 default: io_error( "png_reader_color_convert::read_data(): unknown color type" );
0225 }
0226
0227
0228 png_read_end( this->get_struct()
0229 , nullptr
0230 );
0231 }
0232
0233 private:
0234
0235 template< typename ImagePixel
0236 , typename View
0237 >
0238 void read_rows( const View& view )
0239 {
0240
0241 if (setjmp( png_jmpbuf( this->get_struct() )))
0242 {
0243 io_error("png is invalid");
0244 }
0245
0246 using row_buffer_helper_t = detail::row_buffer_helper_view<ImagePixel>;
0247
0248 using it_t = typename row_buffer_helper_t::iterator_t;
0249
0250 using is_read_and_convert_t = typename std::is_same
0251 <
0252 ConversionPolicy,
0253 detail::read_and_no_convert
0254 >::type;
0255
0256 io_error_if( !detail::is_allowed< View >( this->_info
0257 , is_read_and_convert_t()
0258 )
0259 , "Image types aren't compatible."
0260 );
0261
0262 std::size_t rowbytes = png_get_rowbytes( this->get_struct()
0263 , this->get_info()
0264 );
0265
0266 row_buffer_helper_t buffer( rowbytes
0267 , true
0268 );
0269
0270 png_bytep row_ptr = (png_bytep)( &( buffer.data()[0]));
0271
0272 for( std::size_t pass = 0; pass < this->_number_passes; pass++ )
0273 {
0274 if( pass == this->_number_passes - 1 )
0275 {
0276
0277 for( std::ptrdiff_t y = 0; y < this->_settings._top_left.y; ++y )
0278 {
0279
0280 png_read_rows( this->get_struct()
0281 , &row_ptr
0282 , nullptr
0283 , 1
0284 );
0285 }
0286
0287 for( std::ptrdiff_t y = 0
0288 ; y < this->_settings._dim.y
0289 ; ++y
0290 )
0291 {
0292
0293 png_read_rows( this->get_struct()
0294 , &row_ptr
0295 , nullptr
0296 , 1
0297 );
0298
0299 it_t first = buffer.begin() + this->_settings._top_left.x;
0300 it_t last = first + this->_settings._dim.x;
0301
0302 this->_cc_policy.read( first
0303 , last
0304 , view.row_begin( y ));
0305 }
0306
0307
0308 std::ptrdiff_t remaining_rows = static_cast< std::ptrdiff_t >( this->_info._height )
0309 - this->_settings._top_left.y
0310 - this->_settings._dim.y;
0311 for( std::ptrdiff_t y = 0
0312 ; y < remaining_rows
0313 ; ++y
0314 )
0315 {
0316
0317 png_read_rows( this->get_struct()
0318 , &row_ptr
0319 , nullptr
0320 , 1
0321 );
0322 }
0323 }
0324 else
0325 {
0326 for( int y = 0; y < view.height(); ++y )
0327 {
0328
0329 png_read_rows( this->get_struct()
0330 , &row_ptr
0331 , nullptr
0332 , 1
0333 );
0334 }
0335 }
0336 }
0337 }
0338 };
0339
0340 namespace detail {
0341
0342 struct png_type_format_checker
0343 {
0344 png_type_format_checker( png_bitdepth::type bit_depth
0345 , png_color_type::type color_type
0346 )
0347 : _bit_depth ( bit_depth )
0348 , _color_type( color_type )
0349 {}
0350
0351 template< typename Image >
0352 bool apply()
0353 {
0354 using is_supported_t = is_read_supported
0355 <
0356 typename get_pixel_type<typename Image::view_t>::type,
0357 png_tag
0358 >;
0359
0360 return is_supported_t::_bit_depth == _bit_depth
0361 && is_supported_t::_color_type == _color_type;
0362 }
0363
0364 private:
0365
0366 png_bitdepth::type _bit_depth;
0367 png_color_type::type _color_type;
0368 };
0369
0370 struct png_read_is_supported
0371 {
0372 template< typename View >
0373 struct apply : public is_read_supported< typename get_pixel_type< View >::type
0374 , png_tag
0375 >
0376 {};
0377 };
0378
0379 }
0380
0381
0382
0383
0384
0385 template< typename Device
0386 >
0387 class dynamic_image_reader< Device
0388 , png_tag
0389 >
0390 : public reader< Device
0391 , png_tag
0392 , detail::read_and_no_convert
0393 >
0394 {
0395 using parent_t = reader
0396 <
0397 Device,
0398 png_tag,
0399 detail::read_and_no_convert
0400 >;
0401
0402 public:
0403
0404 dynamic_image_reader( const Device& io_dev
0405 , const image_read_settings< png_tag >& settings
0406 )
0407 : parent_t( io_dev
0408 , settings
0409 )
0410 {}
0411
0412 template< typename ...Images >
0413 void apply( any_image< Images... >& images )
0414 {
0415 detail::png_type_format_checker format_checker( this->_info._bit_depth
0416 , this->_info._color_type
0417 );
0418
0419 if( !detail::construct_matched( images
0420 , format_checker
0421 ))
0422 {
0423 io_error( "No matching image type between those of the given any_image and that of the file" );
0424 }
0425 else
0426 {
0427 this->init_image( images
0428 , this->_settings
0429 );
0430
0431 detail::dynamic_io_fnobj< detail::png_read_is_supported
0432 , parent_t
0433 > op( this );
0434
0435 variant2::visit( op
0436 , view( images )
0437 );
0438 }
0439 }
0440 };
0441
0442 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0443 #pragma warning(pop)
0444 #endif
0445
0446 }
0447 }
0448
0449 #endif