]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/extension/io/tiff/detail/read.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / gil / extension / io / tiff / detail / read.hpp
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
57 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
80 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
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
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 >
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 >
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 >
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 >
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 >
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
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 >
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 >
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 >
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 >
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 >
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 >
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 >
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 >
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 {
690 tiff_type_format_checker( const image_read_info< tiff_tag >& info )
691 : _info( info )
692 {}
693
694 template< typename Image >
695 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:
705 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
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 >
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