Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // Copyright 2007-2012 Christian Henning, Lubomir Bourdev
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_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 // taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
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) //assignment operator could not be generated
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&               /* dst_view */
0081                   , reader< Device
0082                           , tiff_tag
0083                           , ConversionPolicy
0084                           >*                  /* p         */
0085                   )
0086     {}
0087 };
0088 
0089 ///
0090 /// Tiff Reader
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     // only works for homogeneous image types
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             // Steps:
0149             // 1. Read indices. It's an array of grayX_pixel_t.
0150             // 2. Read palette. It's an array of rgb16_pixel_t.
0151             // 3. ??? Create virtual image or transform the two arrays
0152             //    into a rgb16_image_t object. The latter might
0153             //    be a good first solution.
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             // In case we only read the image the user's type and
0174             // the tiff type need to compatible. Which means:
0175             // color_spaces_are_compatible && channels_are_pairwise_compatible
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 // is_read_only
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  // is_read_only
0221              )
0222     {
0223         // the read_data function needs to know what gil type the source image is
0224         // to have the default color converter function correctly
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: // CYMK
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       // read the palette first
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   // is View rgb16_view_t
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&         /* dst_view     */
0361                           , const Indices_View& /* indices_view */
0362                           , std::false_type  // is View rgb16_view_t
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          // Skipping over rows is not possible for compressed images(  no random access ). See man
0376          // page ( diagnostics section ) for more information.
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         /* plane */ )
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           // read a subimage
0415           read_tiled_data_subimage< Buffer >( dst_view, plane );
0416       }
0417       else
0418       {
0419           // read full image
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        ///@todo: why is
0432        /// using row_buffer_helper_t = Buffer;
0433        /// not working? I get compiler error with MSVC10.
0434        /// read_stripped_data IS working.
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                // these are all whole image coordinates
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                    // current tile and dst_view do not overlap
0482                    continue;
0483                }
0484                else
0485                {
0486                    // dst_view is overlapping the current tile
0487 
0488                    // next is to define the portion in the tile that needs to be copied
0489 
0490                    // get the whole image coordinates
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                    // convert to tile coordinates
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                    // convert to dst_view coordinates
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                    // the row_buffer is a 1D array which represents a 2D image. We cannot
0523                    // use interleaved_view here, since row_buffer could be bit_aligned.
0524                    // Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work
0525                    // for bit_aligned pixels.
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                        // jump to the beginning of the current tile row
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                     } //for
0542                }
0543            } // for
0544        } // for
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        ///@todo: why is
0555        /// using row_buffer_helper_t = Buffer;
0556        /// not working? I get compiler error with MSVC10.
0557        /// read_stripped_data IS working.
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                // the row_buffer is a 1D array which represents a 2D image. We cannot
0592                // use interleaved_view here, since row_buffer could be bit_aligned.
0593                // Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work
0594                // for bit_aligned pixels.
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                 } //for
0606            } // for
0607        } // for
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       //using row_buffer_helper_t =detail::row_buffer_helper_view<View>;
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; // one after last element
0630 
0631       // I don't think tiff allows for random access of row, that's why we need
0632       // to read and discard rows when reading subimages.
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 // is_bit_aligned
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 /* width */
0675                             , std::true_type  // is_bit_aligned
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 } // namespace detail
0722 
0723 
0724 ///
0725 /// Tiff Dynamic Image Reader
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 } // namespace gil
0781 } // namespace boost
0782 
0783 #endif