• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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