1 // 2 // Copyright 2007-2012 Christian Henning, Lubomir Bourdev 3 // 4 // Distributed under the Boost Software License, Version 1.0 5 // See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt 7 // 8 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP 9 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP 10 11 #include <boost/gil/extension/io/tiff/detail/device.hpp> 12 #include <boost/gil/extension/io/tiff/detail/is_allowed.hpp> 13 #include <boost/gil/extension/io/tiff/detail/reader_backend.hpp> 14 15 #include <boost/gil/io/base.hpp> 16 #include <boost/gil/io/bit_operations.hpp> 17 #include <boost/gil/io/conversion_policies.hpp> 18 #include <boost/gil/io/device.hpp> 19 #include <boost/gil/io/dynamic_io_new.hpp> 20 #include <boost/gil/io/reader_base.hpp> 21 #include <boost/gil/io/row_buffer_helper.hpp> 22 23 #include <boost/assert.hpp> 24 25 #include <algorithm> 26 #include <string> 27 #include <type_traits> 28 #include <vector> 29 30 // taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp 31 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS 32 extern "C" { 33 #endif 34 35 #include <tiff.h> 36 #include <tiffio.h> 37 38 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS 39 } 40 #endif 41 42 namespace boost { namespace gil { 43 44 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 45 #pragma warning(push) 46 #pragma warning(disable:4512) //assignment operator could not be generated 47 #endif 48 49 template < int K > 50 struct plane_recursion 51 { 52 template< typename View 53 , typename Device 54 , typename ConversionPolicy 55 > 56 static read_planeboost::gil::plane_recursion57 void read_plane( const View& dst_view 58 , reader< Device 59 , tiff_tag 60 , ConversionPolicy >* p 61 ) 62 { 63 using plane_t = typename kth_channel_view_type<K, View>::type; 64 plane_t plane = kth_channel_view<K>( dst_view ); 65 66 p->template read_data< detail::row_buffer_helper_view< plane_t > >( plane, K ); 67 68 plane_recursion< K - 1 >::read_plane( dst_view, p ); 69 } 70 }; 71 72 template <> 73 struct plane_recursion< -1 > 74 { 75 template< typename View 76 , typename Device 77 , typename ConversionPolicy 78 > 79 static read_planeboost::gil::plane_recursion80 void read_plane( const View& /* dst_view */ 81 , reader< Device 82 , tiff_tag 83 , ConversionPolicy 84 >* /* p */ 85 ) 86 {} 87 }; 88 89 /// 90 /// Tiff Reader 91 /// 92 template< typename Device 93 , typename ConversionPolicy 94 > 95 class reader< Device 96 , tiff_tag 97 , ConversionPolicy 98 > 99 : public reader_base< tiff_tag 100 , ConversionPolicy > 101 102 , public reader_backend< Device 103 , tiff_tag 104 > 105 { 106 private: 107 108 using this_t = reader<Device, tiff_tag, ConversionPolicy>; 109 using cc_t = typename ConversionPolicy::color_converter_type; 110 111 public: 112 113 using backend_t = reader_backend<Device, tiff_tag>; 114 reader(const Device & io_dev,const image_read_settings<tiff_tag> & settings)115 reader( const Device& io_dev 116 , const image_read_settings< tiff_tag >& settings 117 ) 118 : reader_base< tiff_tag 119 , ConversionPolicy 120 >() 121 , backend_t( io_dev 122 , settings 123 ) 124 {} 125 reader(const Device & io_dev,const typename ConversionPolicy::color_converter_type & cc,const image_read_settings<tiff_tag> & settings)126 reader( const Device& io_dev 127 , const typename ConversionPolicy::color_converter_type& cc 128 , const image_read_settings< tiff_tag >& settings 129 ) 130 : reader_base< tiff_tag 131 , ConversionPolicy 132 >( cc ) 133 , backend_t( io_dev 134 , settings 135 ) 136 {} 137 138 // only works for homogeneous image types 139 template< typename View > apply(View & dst_view)140 void apply( View& dst_view ) 141 { 142 if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE ) 143 { 144 this->_scanline_length = this->_info._width 145 * num_channels< rgb16_view_t >::value 146 * sizeof( channel_type<rgb16_view_t>::type ); 147 148 // Steps: 149 // 1. Read indices. It's an array of grayX_pixel_t. 150 // 2. Read palette. It's an array of rgb16_pixel_t. 151 // 3. ??? Create virtual image or transform the two arrays 152 // into a rgb16_image_t object. The latter might 153 // be a good first solution. 154 155 switch( this->_info._bits_per_sample ) 156 { 157 case 1: { read_palette_image< gray1_image_t >( dst_view ); break; } 158 case 2: { read_palette_image< gray2_image_t >( dst_view ); break; } 159 case 4: { read_palette_image< gray4_image_t >( dst_view ); break; } 160 case 8: { read_palette_image< gray8_image_t >( dst_view ); break; } 161 case 16: { read_palette_image< gray16_image_t >( dst_view ); break; } 162 163 default: { io_error( "Not supported palette " ); } 164 } 165 166 return; 167 168 } 169 else 170 { 171 this->_scanline_length = this->_io_dev.get_scanline_size(); 172 173 // In case we only read the image the user's type and 174 // the tiff type need to compatible. Which means: 175 // color_spaces_are_compatible && channels_are_pairwise_compatible 176 177 using is_read_only = typename std::is_same 178 < 179 ConversionPolicy, 180 detail::read_and_no_convert 181 >::type; 182 183 io_error_if( !detail::is_allowed< View >( this->_info 184 , is_read_only() 185 ) 186 , "Image types aren't compatible." 187 ); 188 189 if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE ) 190 { 191 plane_recursion< num_channels< View >::value - 1 >::read_plane( dst_view 192 , this 193 ); 194 } 195 else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG ) 196 { 197 read( dst_view 198 , typename is_read_only::type() 199 ); 200 } 201 else 202 { 203 io_error( "Wrong planar configuration setting." ); 204 } 205 } 206 } 207 208 private: 209 210 template< typename View > read(View v,std::true_type)211 void read( View v 212 , std::true_type // is_read_only 213 ) 214 { 215 read_data< detail::row_buffer_helper_view< View > >( v, 0 ); 216 } 217 218 template< typename View > read(View v,std::false_type)219 void read( View v 220 , std::false_type // is_read_only 221 ) 222 { 223 // the read_data function needs to know what gil type the source image is 224 // to have the default color converter function correctly 225 226 switch( this->_info._photometric_interpretation ) 227 { 228 case PHOTOMETRIC_MINISWHITE: 229 case PHOTOMETRIC_MINISBLACK: 230 { 231 switch( this->_info._bits_per_sample ) 232 { 233 case 1: { read_data< detail::row_buffer_helper_view< gray1_image_t::view_t > >( v, 0 ); break; } 234 case 2: { read_data< detail::row_buffer_helper_view< gray2_image_t::view_t > >( v, 0 ); break; } 235 case 4: { read_data< detail::row_buffer_helper_view< gray4_image_t::view_t > >( v, 0 ); break; } 236 case 8: { read_data< detail::row_buffer_helper_view< gray8_view_t > >( v, 0 ); break; } 237 case 16: { read_data< detail::row_buffer_helper_view< gray16_view_t > >( v, 0 ); break; } 238 case 32: { read_data< detail::row_buffer_helper_view< gray32_view_t > >( v, 0 ); break; } 239 default: { io_error( "Image type is not supported." ); } 240 } 241 242 break; 243 } 244 245 case PHOTOMETRIC_RGB: 246 { 247 switch( this->_info._samples_per_pixel ) 248 { 249 case 3: 250 { 251 switch( this->_info._bits_per_sample ) 252 { 253 case 8: { read_data< detail::row_buffer_helper_view< rgb8_view_t > >( v, 0 ); break; } 254 case 16: { read_data< detail::row_buffer_helper_view< rgb16_view_t > >( v, 0 ); break; } 255 case 32: { read_data< detail::row_buffer_helper_view< rgb32_view_t > >( v, 0 ); break; } 256 default: { io_error( "Image type is not supported." ); } 257 } 258 259 break; 260 } 261 262 case 4: 263 { 264 switch( this->_info._bits_per_sample ) 265 { 266 case 8: { read_data< detail::row_buffer_helper_view< rgba8_view_t > >( v, 0 ); break; } 267 case 16: { read_data< detail::row_buffer_helper_view< rgba16_view_t > >( v, 0 ); break; } 268 case 32: { read_data< detail::row_buffer_helper_view< rgba32_view_t > >( v, 0 ); break; } 269 default: { io_error( "Image type is not supported." ); } 270 } 271 272 break; 273 } 274 275 default: { io_error( "Image type is not supported." ); } 276 } 277 278 break; 279 } 280 case PHOTOMETRIC_SEPARATED: // CYMK 281 { 282 switch( this->_info._bits_per_sample ) 283 { 284 case 8: { read_data< detail::row_buffer_helper_view< cmyk8_view_t > >( v, 0 ); break; } 285 case 16: { read_data< detail::row_buffer_helper_view< cmyk16_view_t > >( v, 0 ); break; } 286 case 32: { read_data< detail::row_buffer_helper_view< cmyk32_view_t > >( v, 0 ); break; } 287 default: { io_error( "Image type is not supported." ); } 288 } 289 290 break; 291 } 292 293 default: { io_error( "Image type is not supported." ); } 294 } 295 } 296 297 template< typename PaletteImage 298 , typename View 299 > read_palette_image(const View & dst_view)300 void read_palette_image( const View& dst_view ) 301 { 302 PaletteImage indices( this->_info._width - this->_settings._top_left.x 303 , this->_info._height - this->_settings._top_left.y ); 304 305 // read the palette first 306 read_data< detail::row_buffer_helper_view 307 < 308 typename PaletteImage::view_t> 309 >(view(indices), 0); 310 311 read_palette_image(dst_view, view(indices), 312 typename std::is_same<View, rgb16_view_t>::type()); 313 } 314 315 template< typename View 316 , typename Indices_View 317 > read_palette_image(const View & dst_view,const Indices_View & indices_view,std::true_type)318 void read_palette_image( const View& dst_view 319 , const Indices_View& indices_view 320 , std::true_type // is View rgb16_view_t 321 ) 322 { 323 tiff_color_map::red_t red = nullptr; 324 tiff_color_map::green_t green = nullptr; 325 tiff_color_map::blue_t blue = nullptr; 326 327 this->_io_dev.get_field_defaulted( red, green, blue ); 328 329 using channel_t = typename channel_traits<typename element_type<typename Indices_View::value_type>::type>::value_type; 330 331 int num_colors = channel_traits< channel_t >::max_value(); 332 333 rgb16_planar_view_t palette = planar_rgb_view( num_colors 334 , 1 335 , red 336 , green 337 , blue 338 , sizeof(uint16_t) * num_colors ); 339 340 for( typename rgb16_view_t::y_coord_t y = 0; y < dst_view.height(); ++y ) 341 { 342 typename rgb16_view_t::x_iterator it = dst_view.row_begin( y ); 343 typename rgb16_view_t::x_iterator end = dst_view.row_end( y ); 344 345 typename Indices_View::x_iterator indices_it = indices_view.row_begin( y ); 346 347 for( ; it != end; ++it, ++indices_it ) 348 { 349 uint16_t i = gil::at_c<0>( *indices_it ); 350 351 *it = palette[i]; 352 } 353 } 354 } 355 356 template< typename View 357 , typename Indices_View 358 > 359 inline read_palette_image(const View &,const Indices_View &,std::false_type)360 void read_palette_image( const View& /* dst_view */ 361 , const Indices_View& /* indices_view */ 362 , std::false_type // is View rgb16_view_t 363 ) 364 { 365 io_error( "User supplied image type must be rgb16_image_t." ); 366 } 367 368 template< typename Buffer > skip_over_rows(Buffer & buffer,int plane)369 void skip_over_rows( Buffer& buffer 370 , int plane 371 ) 372 { 373 if( this->_info._compression != COMPRESSION_NONE ) 374 { 375 // Skipping over rows is not possible for compressed images( no random access ). See man 376 // page ( diagnostics section ) for more information. 377 for( std::ptrdiff_t row = 0; row < this->_settings._top_left.y; ++row ) 378 { 379 this->_io_dev.read_scanline( buffer 380 , row 381 , static_cast< tsample_t >( plane )); 382 } 383 } 384 } 385 386 template< typename Buffer 387 , typename View 388 > read_data(const View & dst_view,int)389 void read_data( const View& dst_view 390 , int /* plane */ ) 391 { 392 if( this->_io_dev.is_tiled() ) 393 { 394 read_tiled_data< Buffer >( dst_view, 0 ); 395 } 396 else 397 { 398 read_stripped_data< Buffer >( dst_view, 0 ); 399 } 400 } 401 402 403 template< typename Buffer 404 , typename View 405 > read_tiled_data(const View & dst_view,int plane)406 void read_tiled_data( const View& dst_view 407 , int plane 408 ) 409 { 410 if( dst_view.width() != this->_info._width 411 || dst_view.height() != this->_info._height 412 ) 413 { 414 // read a subimage 415 read_tiled_data_subimage< Buffer >( dst_view, plane ); 416 } 417 else 418 { 419 // read full image 420 read_tiled_data_full< Buffer >( dst_view, plane ); 421 } 422 } 423 424 template< typename Buffer 425 , typename View 426 > read_tiled_data_subimage(const View & dst_view,int plane)427 void read_tiled_data_subimage( const View& dst_view 428 , int plane 429 ) 430 { 431 ///@todo: why is 432 /// using row_buffer_helper_t = Buffer; 433 /// not working? I get compiler error with MSVC10. 434 /// read_stripped_data IS working. 435 using row_buffer_helper_t = detail::row_buffer_helper_view<View>; 436 437 using it_t = typename row_buffer_helper_t::iterator_t; 438 439 tiff_image_width::type image_width = this->_info._width; 440 tiff_image_height::type image_height = this->_info._height; 441 442 tiff_tile_width::type tile_width = this->_info._tile_width; 443 tiff_tile_length::type tile_height = this->_info._tile_length; 444 445 std::ptrdiff_t subimage_x = this->_settings._top_left.x; 446 std::ptrdiff_t subimage_y = this->_settings._top_left.y; 447 448 std::ptrdiff_t subimage_width = this->_settings._dim.x; 449 std::ptrdiff_t subimage_height = this->_settings._dim.y; 450 451 row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true ); 452 453 for( unsigned int y = 0; y < image_height; y += tile_height ) 454 { 455 for( unsigned int x = 0; x < image_width; x += tile_width ) 456 { 457 uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x; 458 uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y; 459 460 this->_io_dev.read_tile( row_buffer_helper.buffer() 461 , x 462 , y 463 , 0 464 , static_cast< tsample_t >( plane ) 465 ); 466 467 // these are all whole image coordinates 468 point_t tile_top_left ( x, y ); 469 point_t tile_lower_right( x + current_tile_width - 1, y + current_tile_length - 1 ); 470 471 point_t view_top_left ( subimage_x, subimage_y ); 472 point_t view_lower_right( subimage_x + subimage_width - 1 473 , subimage_y + subimage_height - 1 ); 474 475 if( tile_top_left.x > view_lower_right.x 476 || tile_top_left.y > view_lower_right.y 477 || tile_lower_right.x < view_top_left.x 478 || tile_lower_right.y < view_top_left.y 479 ) 480 { 481 // current tile and dst_view do not overlap 482 continue; 483 } 484 else 485 { 486 // dst_view is overlapping the current tile 487 488 // next is to define the portion in the tile that needs to be copied 489 490 // get the whole image coordinates 491 std::ptrdiff_t img_x0 = ( tile_top_left.x >= view_top_left.x ) ? tile_top_left.x : view_top_left.x; 492 std::ptrdiff_t img_y0 = ( tile_top_left.y >= view_top_left.y ) ? tile_top_left.y : view_top_left.y; 493 494 std::ptrdiff_t img_x1 = ( tile_lower_right.x <= view_lower_right.x ) ? tile_lower_right.x : view_lower_right.x; 495 std::ptrdiff_t img_y1 = ( tile_lower_right.y <= view_lower_right.y ) ? tile_lower_right.y : view_lower_right.y; 496 497 // convert to tile coordinates 498 std::ptrdiff_t tile_x0 = img_x0 - x; 499 std::ptrdiff_t tile_y0 = img_y0 - y; 500 std::ptrdiff_t tile_x1 = img_x1 - x; 501 std::ptrdiff_t tile_y1 = img_y1 - y; 502 503 BOOST_ASSERT(tile_x0 >= 0 && tile_y0 >= 0 && tile_x1 >= 0 && tile_y1 >= 0); 504 BOOST_ASSERT(tile_x0 <= img_x1 && tile_y0 <= img_y1); 505 BOOST_ASSERT(tile_x0 < tile_width && tile_y0 < tile_height && tile_x1 < tile_width && tile_y1 < tile_height); 506 507 std::ptrdiff_t tile_subimage_view_width = tile_x1 - tile_x0 + 1; 508 std::ptrdiff_t tile_subimage_view_height = tile_y1 - tile_y0 + 1; 509 510 // convert to dst_view coordinates 511 std::ptrdiff_t dst_x0 = img_x0 - subimage_x; 512 std::ptrdiff_t dst_y0 = img_y0 - subimage_y; 513 BOOST_ASSERT(dst_x0 >= 0 && dst_y0 >= 0); 514 515 View dst_subimage_view = subimage_view( dst_view 516 , (int) dst_x0 517 , (int) dst_y0 518 , (int) tile_subimage_view_width 519 , (int) tile_subimage_view_height 520 ); 521 522 // the row_buffer is a 1D array which represents a 2D image. We cannot 523 // use interleaved_view here, since row_buffer could be bit_aligned. 524 // Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work 525 // for bit_aligned pixels. 526 527 for( std::ptrdiff_t dst_row = 0; dst_row < dst_subimage_view.height(); ++dst_row ) 528 { 529 std::ptrdiff_t tile_row = dst_row + tile_y0; 530 531 // jump to the beginning of the current tile row 532 it_t begin = row_buffer_helper.begin() + tile_row * tile_width; 533 534 begin += tile_x0; 535 it_t end = begin + dst_subimage_view.width(); 536 537 this->_cc_policy.read( begin 538 , end 539 , dst_subimage_view.row_begin( dst_row ) 540 ); 541 } //for 542 } 543 } // for 544 } // for 545 } 546 547 template< typename Buffer 548 , typename View 549 > read_tiled_data_full(const View & dst_view,int plane)550 void read_tiled_data_full( const View& dst_view 551 , int plane 552 ) 553 { 554 ///@todo: why is 555 /// using row_buffer_helper_t = Buffer; 556 /// not working? I get compiler error with MSVC10. 557 /// read_stripped_data IS working. 558 using row_buffer_helper_t = detail::row_buffer_helper_view<View>; 559 560 using it_t = typename row_buffer_helper_t::iterator_t; 561 562 tiff_image_width::type image_width = this->_info._width; 563 tiff_image_height::type image_height = this->_info._height; 564 565 tiff_tile_width::type tile_width = this->_info._tile_width; 566 tiff_tile_length::type tile_height = this->_info._tile_length; 567 568 row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true ); 569 570 for( unsigned int y = 0; y < image_height; y += tile_height ) 571 { 572 for( unsigned int x = 0; x < image_width; x += tile_width ) 573 { 574 uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x; 575 uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y; 576 577 this->_io_dev.read_tile( row_buffer_helper.buffer() 578 , x 579 , y 580 , 0 581 , static_cast< tsample_t >( plane ) 582 ); 583 584 View dst_subimage_view = subimage_view( dst_view 585 , x 586 , y 587 , current_tile_width 588 , current_tile_length 589 ); 590 591 // the row_buffer is a 1D array which represents a 2D image. We cannot 592 // use interleaved_view here, since row_buffer could be bit_aligned. 593 // Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work 594 // for bit_aligned pixels. 595 596 for( int row = 0; row < dst_subimage_view.height(); ++row ) 597 { 598 it_t begin = row_buffer_helper.begin() + row * tile_width; 599 it_t end = begin + dst_subimage_view.width(); 600 601 this->_cc_policy.read( begin 602 , end 603 , dst_subimage_view.row_begin( row ) 604 ); 605 } //for 606 } // for 607 } // for 608 } 609 610 template< typename Buffer 611 , typename View 612 > read_stripped_data(const View & dst_view,int plane)613 void read_stripped_data( const View& dst_view 614 , int plane ) 615 { 616 using is_view_bit_aligned_t = typename is_bit_aligned<typename View::value_type>::type; 617 618 //using row_buffer_helper_t =detail::row_buffer_helper_view<View>; 619 using row_buffer_helper_t = Buffer; 620 using it_t = typename row_buffer_helper_t::iterator_t; 621 622 std::size_t size_to_allocate = buffer_size< typename View::value_type >( dst_view.width() 623 , is_view_bit_aligned_t() ); 624 row_buffer_helper_t row_buffer_helper( size_to_allocate, true ); 625 626 it_t begin = row_buffer_helper.begin(); 627 628 it_t first = begin + this->_settings._top_left.x; 629 it_t last = first + this->_settings._dim.x; // one after last element 630 631 // I don't think tiff allows for random access of row, that's why we need 632 // to read and discard rows when reading subimages. 633 skip_over_rows( row_buffer_helper.buffer() 634 , plane 635 ); 636 637 std::ptrdiff_t row = this->_settings._top_left.y; 638 std::ptrdiff_t row_end = row + this->_settings._dim.y; 639 std::ptrdiff_t dst_row = 0; 640 641 for( 642 ; row < row_end 643 ; ++row, ++dst_row 644 ) 645 { 646 this->_io_dev.read_scanline( row_buffer_helper.buffer() 647 , row 648 , static_cast< tsample_t >( plane ) 649 ); 650 651 this->_cc_policy.read( first 652 , last 653 , dst_view.row_begin( dst_row )); 654 } 655 } 656 657 template< typename Pixel > buffer_size(std::size_t width,std::false_type)658 std::size_t buffer_size( std::size_t width 659 , std::false_type // is_bit_aligned 660 ) 661 { 662 std::size_t scanline_size_in_bytes = this->_io_dev.get_scanline_size(); 663 664 std::size_t element_size = sizeof( Pixel ); 665 666 std::size_t ret = std::max( width 667 , (( scanline_size_in_bytes + element_size - 1 ) / element_size ) 668 ); 669 670 return ret; 671 } 672 673 template< typename Pixel > buffer_size(std::size_t,std::true_type)674 std::size_t buffer_size( std::size_t /* width */ 675 , std::true_type // is_bit_aligned 676 ) 677 { 678 return this->_io_dev.get_scanline_size(); 679 } 680 681 private: 682 683 template < int K > friend struct plane_recursion; 684 }; 685 686 namespace detail { 687 688 struct tiff_type_format_checker 689 { tiff_type_format_checkerboost::gil::detail::tiff_type_format_checker690 tiff_type_format_checker( const image_read_info< tiff_tag >& info ) 691 : _info( info ) 692 {} 693 694 template< typename Image > applyboost::gil::detail::tiff_type_format_checker695 bool apply() 696 { 697 using view_t = typename Image::view_t; 698 699 return is_allowed< view_t >( _info 700 , std::true_type() 701 ); 702 } 703 704 private: operator =boost::gil::detail::tiff_type_format_checker705 tiff_type_format_checker& operator=( const tiff_type_format_checker& ) { return *this; } 706 707 private: 708 709 const image_read_info< tiff_tag > _info; 710 }; 711 712 struct tiff_read_is_supported 713 { 714 template< typename View > 715 struct apply : public is_read_supported< typename get_pixel_type< View >::type 716 , tiff_tag 717 > 718 {}; 719 }; 720 721 } // namespace detail 722 723 724 /// 725 /// Tiff Dynamic Image Reader 726 /// 727 template< typename Device > 728 class dynamic_image_reader< Device 729 , tiff_tag 730 > 731 : public reader< Device 732 , tiff_tag 733 , detail::read_and_no_convert 734 > 735 { 736 using parent_t = reader<Device, tiff_tag, detail::read_and_no_convert>; 737 738 public: 739 dynamic_image_reader(const Device & io_dev,const image_read_settings<tiff_tag> & settings)740 dynamic_image_reader( const Device& io_dev 741 , const image_read_settings< tiff_tag >& settings 742 ) 743 : parent_t( io_dev 744 , settings 745 ) 746 {} 747 748 template< typename ...Images > apply(any_image<Images...> & images)749 void apply( any_image< Images... >& images ) 750 { 751 detail::tiff_type_format_checker format_checker( this->_info ); 752 753 if( !construct_matched( images 754 , format_checker 755 )) 756 { 757 io_error( "No matching image type between those of the given any_image and that of the file" ); 758 } 759 else 760 { 761 this->init_image( images 762 , this->_settings 763 ); 764 765 detail::dynamic_io_fnobj< detail::tiff_read_is_supported 766 , parent_t 767 > op( this ); 768 769 apply_operation( view( images ) 770 , op 771 ); 772 } 773 } 774 }; 775 776 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 777 #pragma warning(pop) 778 #endif 779 780 } // namespace gil 781 } // namespace boost 782 783 #endif 784