File indexing completed on 2025-01-18 09:36:59
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP
0009 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP
0010
0011 #include <boost/gil/extension/io/tiff/detail/device.hpp>
0012 #include <boost/gil/extension/io/tiff/detail/is_allowed.hpp>
0013 #include <boost/gil/extension/io/tiff/detail/reader_backend.hpp>
0014
0015 #include <boost/gil/io/detail/dynamic.hpp>
0016 #include <boost/gil/io/base.hpp>
0017 #include <boost/gil/io/bit_operations.hpp>
0018 #include <boost/gil/io/conversion_policies.hpp>
0019 #include <boost/gil/io/device.hpp>
0020 #include <boost/gil/io/reader_base.hpp>
0021 #include <boost/gil/io/row_buffer_helper.hpp>
0022
0023 #include <boost/assert.hpp>
0024
0025 #include <algorithm>
0026 #include <string>
0027 #include <type_traits>
0028 #include <vector>
0029
0030
0031 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
0032 extern "C" {
0033 #endif
0034
0035 #include <tiff.h>
0036 #include <tiffio.h>
0037
0038 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
0039 }
0040 #endif
0041
0042 namespace boost { namespace gil {
0043
0044 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0045 #pragma warning(push)
0046 #pragma warning(disable:4512)
0047 #endif
0048
0049 template < int K >
0050 struct plane_recursion
0051 {
0052 template< typename View
0053 , typename Device
0054 , typename ConversionPolicy
0055 >
0056 static
0057 void read_plane( const View& dst_view
0058 , reader< Device
0059 , tiff_tag
0060 , ConversionPolicy >* p
0061 )
0062 {
0063 using plane_t = typename kth_channel_view_type<K, View>::type;
0064 plane_t plane = kth_channel_view<K>( dst_view );
0065
0066 p->template read_data< detail::row_buffer_helper_view< plane_t > >( plane, K );
0067
0068 plane_recursion< K - 1 >::read_plane( dst_view, p );
0069 }
0070 };
0071
0072 template <>
0073 struct plane_recursion< -1 >
0074 {
0075 template< typename View
0076 , typename Device
0077 , typename ConversionPolicy
0078 >
0079 static
0080 void read_plane( const View&
0081 , reader< Device
0082 , tiff_tag
0083 , ConversionPolicy
0084 >*
0085 )
0086 {}
0087 };
0088
0089
0090
0091
0092 template< typename Device
0093 , typename ConversionPolicy
0094 >
0095 class reader< Device
0096 , tiff_tag
0097 , ConversionPolicy
0098 >
0099 : public reader_base< tiff_tag
0100 , ConversionPolicy >
0101
0102 , public reader_backend< Device
0103 , tiff_tag
0104 >
0105 {
0106 private:
0107
0108 using this_t = reader<Device, tiff_tag, ConversionPolicy>;
0109 using cc_t = typename ConversionPolicy::color_converter_type;
0110
0111 public:
0112
0113 using backend_t = reader_backend<Device, tiff_tag>;
0114
0115 reader( const Device& io_dev
0116 , const image_read_settings< tiff_tag >& settings
0117 )
0118 : reader_base< tiff_tag
0119 , ConversionPolicy
0120 >()
0121 , backend_t( io_dev
0122 , settings
0123 )
0124 {}
0125
0126 reader( const Device& io_dev
0127 , const typename ConversionPolicy::color_converter_type& cc
0128 , const image_read_settings< tiff_tag >& settings
0129 )
0130 : reader_base< tiff_tag
0131 , ConversionPolicy
0132 >( cc )
0133 , backend_t( io_dev
0134 , settings
0135 )
0136 {}
0137
0138
0139 template< typename View >
0140 void apply( View& dst_view )
0141 {
0142 if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE )
0143 {
0144 this->_scanline_length = this->_info._width
0145 * num_channels< rgb16_view_t >::value
0146 * sizeof( channel_type<rgb16_view_t>::type );
0147
0148
0149
0150
0151
0152
0153
0154
0155 switch( this->_info._bits_per_sample )
0156 {
0157 case 1: { read_palette_image< gray1_image_t >( dst_view ); break; }
0158 case 2: { read_palette_image< gray2_image_t >( dst_view ); break; }
0159 case 4: { read_palette_image< gray4_image_t >( dst_view ); break; }
0160 case 8: { read_palette_image< gray8_image_t >( dst_view ); break; }
0161 case 16: { read_palette_image< gray16_image_t >( dst_view ); break; }
0162
0163 default: { io_error( "Not supported palette " ); }
0164 }
0165
0166 return;
0167
0168 }
0169 else
0170 {
0171 this->_scanline_length = this->_io_dev.get_scanline_size();
0172
0173
0174
0175
0176
0177 using is_read_only = typename std::is_same
0178 <
0179 ConversionPolicy,
0180 detail::read_and_no_convert
0181 >::type;
0182
0183 io_error_if( !detail::is_allowed< View >( this->_info
0184 , is_read_only()
0185 )
0186 , "Image types aren't compatible."
0187 );
0188
0189 if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE )
0190 {
0191 plane_recursion< num_channels< View >::value - 1 >::read_plane( dst_view
0192 , this
0193 );
0194 }
0195 else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG )
0196 {
0197 read( dst_view
0198 , typename is_read_only::type()
0199 );
0200 }
0201 else
0202 {
0203 io_error( "Wrong planar configuration setting." );
0204 }
0205 }
0206 }
0207
0208 private:
0209
0210 template< typename View >
0211 void read( View v
0212 , std::true_type
0213 )
0214 {
0215 read_data< detail::row_buffer_helper_view< View > >( v, 0 );
0216 }
0217
0218 template< typename View >
0219 void read( View v
0220 , std::false_type
0221 )
0222 {
0223
0224
0225
0226 switch( this->_info._photometric_interpretation )
0227 {
0228 case PHOTOMETRIC_MINISWHITE:
0229 case PHOTOMETRIC_MINISBLACK:
0230 {
0231 switch( this->_info._bits_per_sample )
0232 {
0233 case 1: { read_data< detail::row_buffer_helper_view< gray1_image_t::view_t > >( v, 0 ); break; }
0234 case 2: { read_data< detail::row_buffer_helper_view< gray2_image_t::view_t > >( v, 0 ); break; }
0235 case 4: { read_data< detail::row_buffer_helper_view< gray4_image_t::view_t > >( v, 0 ); break; }
0236 case 8: { read_data< detail::row_buffer_helper_view< gray8_view_t > >( v, 0 ); break; }
0237 case 16: { read_data< detail::row_buffer_helper_view< gray16_view_t > >( v, 0 ); break; }
0238 case 32: { read_data< detail::row_buffer_helper_view< gray32_view_t > >( v, 0 ); break; }
0239 default: { io_error( "Image type is not supported." ); }
0240 }
0241
0242 break;
0243 }
0244
0245 case PHOTOMETRIC_RGB:
0246 {
0247 switch( this->_info._samples_per_pixel )
0248 {
0249 case 3:
0250 {
0251 switch( this->_info._bits_per_sample )
0252 {
0253 case 8: { read_data< detail::row_buffer_helper_view< rgb8_view_t > >( v, 0 ); break; }
0254 case 16: { read_data< detail::row_buffer_helper_view< rgb16_view_t > >( v, 0 ); break; }
0255 case 32: { read_data< detail::row_buffer_helper_view< rgb32_view_t > >( v, 0 ); break; }
0256 default: { io_error( "Image type is not supported." ); }
0257 }
0258
0259 break;
0260 }
0261
0262 case 4:
0263 {
0264 switch( this->_info._bits_per_sample )
0265 {
0266 case 8: { read_data< detail::row_buffer_helper_view< rgba8_view_t > >( v, 0 ); break; }
0267 case 16: { read_data< detail::row_buffer_helper_view< rgba16_view_t > >( v, 0 ); break; }
0268 case 32: { read_data< detail::row_buffer_helper_view< rgba32_view_t > >( v, 0 ); break; }
0269 default: { io_error( "Image type is not supported." ); }
0270 }
0271
0272 break;
0273 }
0274
0275 default: { io_error( "Image type is not supported." ); }
0276 }
0277
0278 break;
0279 }
0280 case PHOTOMETRIC_SEPARATED:
0281 {
0282 switch( this->_info._bits_per_sample )
0283 {
0284 case 8: { read_data< detail::row_buffer_helper_view< cmyk8_view_t > >( v, 0 ); break; }
0285 case 16: { read_data< detail::row_buffer_helper_view< cmyk16_view_t > >( v, 0 ); break; }
0286 case 32: { read_data< detail::row_buffer_helper_view< cmyk32_view_t > >( v, 0 ); break; }
0287 default: { io_error( "Image type is not supported." ); }
0288 }
0289
0290 break;
0291 }
0292
0293 default: { io_error( "Image type is not supported." ); }
0294 }
0295 }
0296
0297 template< typename PaletteImage
0298 , typename View
0299 >
0300 void read_palette_image( const View& dst_view )
0301 {
0302 PaletteImage indices( this->_info._width - this->_settings._top_left.x
0303 , this->_info._height - this->_settings._top_left.y );
0304
0305
0306 read_data< detail::row_buffer_helper_view
0307 <
0308 typename PaletteImage::view_t>
0309 >(view(indices), 0);
0310
0311 read_palette_image(dst_view, view(indices),
0312 typename std::is_same<View, rgb16_view_t>::type());
0313 }
0314
0315 template< typename View
0316 , typename Indices_View
0317 >
0318 void read_palette_image( const View& dst_view
0319 , const Indices_View& indices_view
0320 , std::true_type
0321 )
0322 {
0323 tiff_color_map::red_t red = nullptr;
0324 tiff_color_map::green_t green = nullptr;
0325 tiff_color_map::blue_t blue = nullptr;
0326
0327 this->_io_dev.get_field_defaulted( red, green, blue );
0328
0329 using channel_t = typename channel_traits<typename element_type<typename Indices_View::value_type>::type>::value_type;
0330
0331 int num_colors = channel_traits< channel_t >::max_value();
0332
0333 rgb16_planar_view_t palette = planar_rgb_view( num_colors
0334 , 1
0335 , red
0336 , green
0337 , blue
0338 , sizeof(uint16_t) * num_colors );
0339
0340 for( typename rgb16_view_t::y_coord_t y = 0; y < dst_view.height(); ++y )
0341 {
0342 typename rgb16_view_t::x_iterator it = dst_view.row_begin( y );
0343 typename rgb16_view_t::x_iterator end = dst_view.row_end( y );
0344
0345 typename Indices_View::x_iterator indices_it = indices_view.row_begin( y );
0346
0347 for( ; it != end; ++it, ++indices_it )
0348 {
0349 uint16_t i = gil::at_c<0>( *indices_it );
0350
0351 *it = palette[i];
0352 }
0353 }
0354 }
0355
0356 template< typename View
0357 , typename Indices_View
0358 >
0359 inline
0360 void read_palette_image( const View&
0361 , const Indices_View&
0362 , std::false_type
0363 )
0364 {
0365 io_error( "User supplied image type must be rgb16_image_t." );
0366 }
0367
0368 template< typename Buffer >
0369 void skip_over_rows( Buffer& buffer
0370 , int plane
0371 )
0372 {
0373 if( this->_info._compression != COMPRESSION_NONE )
0374 {
0375
0376
0377 for( std::ptrdiff_t row = 0; row < this->_settings._top_left.y; ++row )
0378 {
0379 this->_io_dev.read_scanline( buffer
0380 , row
0381 , static_cast< tsample_t >( plane ));
0382 }
0383 }
0384 }
0385
0386 template< typename Buffer
0387 , typename View
0388 >
0389 void read_data( const View& dst_view
0390 , int )
0391 {
0392 if( this->_io_dev.is_tiled() )
0393 {
0394 read_tiled_data< Buffer >( dst_view, 0 );
0395 }
0396 else
0397 {
0398 read_stripped_data< Buffer >( dst_view, 0 );
0399 }
0400 }
0401
0402
0403 template< typename Buffer
0404 , typename View
0405 >
0406 void read_tiled_data( const View& dst_view
0407 , int plane
0408 )
0409 {
0410 if( dst_view.width() != this->_info._width
0411 || dst_view.height() != this->_info._height
0412 )
0413 {
0414
0415 read_tiled_data_subimage< Buffer >( dst_view, plane );
0416 }
0417 else
0418 {
0419
0420 read_tiled_data_full< Buffer >( dst_view, plane );
0421 }
0422 }
0423
0424 template< typename Buffer
0425 , typename View
0426 >
0427 void read_tiled_data_subimage( const View& dst_view
0428 , int plane
0429 )
0430 {
0431
0432
0433
0434
0435 using row_buffer_helper_t = detail::row_buffer_helper_view<View>;
0436
0437 using it_t = typename row_buffer_helper_t::iterator_t;
0438
0439 tiff_image_width::type image_width = this->_info._width;
0440 tiff_image_height::type image_height = this->_info._height;
0441
0442 tiff_tile_width::type tile_width = this->_info._tile_width;
0443 tiff_tile_length::type tile_height = this->_info._tile_length;
0444
0445 std::ptrdiff_t subimage_x = this->_settings._top_left.x;
0446 std::ptrdiff_t subimage_y = this->_settings._top_left.y;
0447
0448 std::ptrdiff_t subimage_width = this->_settings._dim.x;
0449 std::ptrdiff_t subimage_height = this->_settings._dim.y;
0450
0451 row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true );
0452
0453 for( unsigned int y = 0; y < image_height; y += tile_height )
0454 {
0455 for( unsigned int x = 0; x < image_width; x += tile_width )
0456 {
0457 uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x;
0458 uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y;
0459
0460 this->_io_dev.read_tile( row_buffer_helper.buffer()
0461 , x
0462 , y
0463 , 0
0464 , static_cast< tsample_t >( plane )
0465 );
0466
0467
0468 point_t tile_top_left ( x, y );
0469 point_t tile_lower_right( x + current_tile_width - 1, y + current_tile_length - 1 );
0470
0471 point_t view_top_left ( subimage_x, subimage_y );
0472 point_t view_lower_right( subimage_x + subimage_width - 1
0473 , subimage_y + subimage_height - 1 );
0474
0475 if( tile_top_left.x > view_lower_right.x
0476 || tile_top_left.y > view_lower_right.y
0477 || tile_lower_right.x < view_top_left.x
0478 || tile_lower_right.y < view_top_left.y
0479 )
0480 {
0481
0482 continue;
0483 }
0484 else
0485 {
0486
0487
0488
0489
0490
0491 std::ptrdiff_t img_x0 = ( tile_top_left.x >= view_top_left.x ) ? tile_top_left.x : view_top_left.x;
0492 std::ptrdiff_t img_y0 = ( tile_top_left.y >= view_top_left.y ) ? tile_top_left.y : view_top_left.y;
0493
0494 std::ptrdiff_t img_x1 = ( tile_lower_right.x <= view_lower_right.x ) ? tile_lower_right.x : view_lower_right.x;
0495 std::ptrdiff_t img_y1 = ( tile_lower_right.y <= view_lower_right.y ) ? tile_lower_right.y : view_lower_right.y;
0496
0497
0498 std::ptrdiff_t tile_x0 = img_x0 - x;
0499 std::ptrdiff_t tile_y0 = img_y0 - y;
0500 std::ptrdiff_t tile_x1 = img_x1 - x;
0501 std::ptrdiff_t tile_y1 = img_y1 - y;
0502
0503 BOOST_ASSERT(tile_x0 >= 0 && tile_y0 >= 0 && tile_x1 >= 0 && tile_y1 >= 0);
0504 BOOST_ASSERT(tile_x0 <= img_x1 && tile_y0 <= img_y1);
0505 BOOST_ASSERT(tile_x0 < tile_width && tile_y0 < tile_height && tile_x1 < tile_width && tile_y1 < tile_height);
0506
0507 std::ptrdiff_t tile_subimage_view_width = tile_x1 - tile_x0 + 1;
0508 std::ptrdiff_t tile_subimage_view_height = tile_y1 - tile_y0 + 1;
0509
0510
0511 std::ptrdiff_t dst_x0 = img_x0 - subimage_x;
0512 std::ptrdiff_t dst_y0 = img_y0 - subimage_y;
0513 BOOST_ASSERT(dst_x0 >= 0 && dst_y0 >= 0);
0514
0515 View dst_subimage_view = subimage_view( dst_view
0516 , (int) dst_x0
0517 , (int) dst_y0
0518 , (int) tile_subimage_view_width
0519 , (int) tile_subimage_view_height
0520 );
0521
0522
0523
0524
0525
0526
0527 for( std::ptrdiff_t dst_row = 0; dst_row < dst_subimage_view.height(); ++dst_row )
0528 {
0529 std::ptrdiff_t tile_row = dst_row + tile_y0;
0530
0531
0532 it_t begin = row_buffer_helper.begin() + tile_row * tile_width;
0533
0534 begin += tile_x0;
0535 it_t end = begin + dst_subimage_view.width();
0536
0537 this->_cc_policy.read( begin
0538 , end
0539 , dst_subimage_view.row_begin( dst_row )
0540 );
0541 }
0542 }
0543 }
0544 }
0545 }
0546
0547 template< typename Buffer
0548 , typename View
0549 >
0550 void read_tiled_data_full( const View& dst_view
0551 , int plane
0552 )
0553 {
0554
0555
0556
0557
0558 using row_buffer_helper_t = detail::row_buffer_helper_view<View>;
0559
0560 using it_t = typename row_buffer_helper_t::iterator_t;
0561
0562 tiff_image_width::type image_width = this->_info._width;
0563 tiff_image_height::type image_height = this->_info._height;
0564
0565 tiff_tile_width::type tile_width = this->_info._tile_width;
0566 tiff_tile_length::type tile_height = this->_info._tile_length;
0567
0568 row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true );
0569
0570 for( unsigned int y = 0; y < image_height; y += tile_height )
0571 {
0572 for( unsigned int x = 0; x < image_width; x += tile_width )
0573 {
0574 uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x;
0575 uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y;
0576
0577 this->_io_dev.read_tile( row_buffer_helper.buffer()
0578 , x
0579 , y
0580 , 0
0581 , static_cast< tsample_t >( plane )
0582 );
0583
0584 View dst_subimage_view = subimage_view( dst_view
0585 , x
0586 , y
0587 , current_tile_width
0588 , current_tile_length
0589 );
0590
0591
0592
0593
0594
0595
0596 for( int row = 0; row < dst_subimage_view.height(); ++row )
0597 {
0598 it_t begin = row_buffer_helper.begin() + row * tile_width;
0599 it_t end = begin + dst_subimage_view.width();
0600
0601 this->_cc_policy.read( begin
0602 , end
0603 , dst_subimage_view.row_begin( row )
0604 );
0605 }
0606 }
0607 }
0608 }
0609
0610 template< typename Buffer
0611 , typename View
0612 >
0613 void read_stripped_data( const View& dst_view
0614 , int plane )
0615 {
0616 using is_view_bit_aligned_t = typename is_bit_aligned<typename View::value_type>::type;
0617
0618
0619 using row_buffer_helper_t = Buffer;
0620 using it_t = typename row_buffer_helper_t::iterator_t;
0621
0622 std::size_t size_to_allocate = buffer_size< typename View::value_type >( dst_view.width()
0623 , is_view_bit_aligned_t() );
0624 row_buffer_helper_t row_buffer_helper( size_to_allocate, true );
0625
0626 it_t begin = row_buffer_helper.begin();
0627
0628 it_t first = begin + this->_settings._top_left.x;
0629 it_t last = first + this->_settings._dim.x;
0630
0631
0632
0633 skip_over_rows( row_buffer_helper.buffer()
0634 , plane
0635 );
0636
0637 std::ptrdiff_t row = this->_settings._top_left.y;
0638 std::ptrdiff_t row_end = row + this->_settings._dim.y;
0639 std::ptrdiff_t dst_row = 0;
0640
0641 for(
0642 ; row < row_end
0643 ; ++row, ++dst_row
0644 )
0645 {
0646 this->_io_dev.read_scanline( row_buffer_helper.buffer()
0647 , row
0648 , static_cast< tsample_t >( plane )
0649 );
0650
0651 this->_cc_policy.read( first
0652 , last
0653 , dst_view.row_begin( dst_row ));
0654 }
0655 }
0656
0657 template< typename Pixel >
0658 std::size_t buffer_size( std::size_t width
0659 , std::false_type
0660 )
0661 {
0662 std::size_t scanline_size_in_bytes = this->_io_dev.get_scanline_size();
0663
0664 std::size_t element_size = sizeof( Pixel );
0665
0666 std::size_t ret = std::max( width
0667 , (( scanline_size_in_bytes + element_size - 1 ) / element_size )
0668 );
0669
0670 return ret;
0671 }
0672
0673 template< typename Pixel >
0674 std::size_t buffer_size( std::size_t
0675 , std::true_type
0676 )
0677 {
0678 return this->_io_dev.get_scanline_size();
0679 }
0680
0681 private:
0682
0683 template < int K > friend struct plane_recursion;
0684 };
0685
0686 namespace detail {
0687
0688 struct tiff_type_format_checker
0689 {
0690 tiff_type_format_checker( const image_read_info< tiff_tag >& info )
0691 : _info( info )
0692 {}
0693
0694 template< typename Image >
0695 bool apply()
0696 {
0697 using view_t = typename Image::view_t;
0698
0699 return is_allowed< view_t >( _info
0700 , std::true_type()
0701 );
0702 }
0703
0704 private:
0705 tiff_type_format_checker& operator=( const tiff_type_format_checker& ) { return *this; }
0706
0707 private:
0708
0709 const image_read_info< tiff_tag > _info;
0710 };
0711
0712 struct tiff_read_is_supported
0713 {
0714 template< typename View >
0715 struct apply : public is_read_supported< typename get_pixel_type< View >::type
0716 , tiff_tag
0717 >
0718 {};
0719 };
0720
0721 }
0722
0723
0724
0725
0726
0727 template< typename Device >
0728 class dynamic_image_reader< Device
0729 , tiff_tag
0730 >
0731 : public reader< Device
0732 , tiff_tag
0733 , detail::read_and_no_convert
0734 >
0735 {
0736 using parent_t = reader<Device, tiff_tag, detail::read_and_no_convert>;
0737
0738 public:
0739
0740 dynamic_image_reader( const Device& io_dev
0741 , const image_read_settings< tiff_tag >& settings
0742 )
0743 : parent_t( io_dev
0744 , settings
0745 )
0746 {}
0747
0748 template< typename ...Images >
0749 void apply( any_image< Images... >& images )
0750 {
0751 detail::tiff_type_format_checker format_checker( this->_info );
0752
0753 if( !construct_matched( images
0754 , format_checker
0755 ))
0756 {
0757 io_error( "No matching image type between those of the given any_image and that of the file" );
0758 }
0759 else
0760 {
0761 this->init_image( images
0762 , this->_settings
0763 );
0764
0765 detail::dynamic_io_fnobj< detail::tiff_read_is_supported
0766 , parent_t
0767 > op( this );
0768
0769 variant2::visit( op
0770 , view( images )
0771 );
0772 }
0773 }
0774 };
0775
0776 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0777 #pragma warning(pop)
0778 #endif
0779
0780 }
0781 }
0782
0783 #endif