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_SCANLINE_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SCANLINE_READ_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/reader_base.hpp>
20 #include <boost/gil/io/row_buffer_helper.hpp>
21 #include <boost/gil/io/scanline_read_iterator.hpp>
22 
23 #include <algorithm>
24 #include <functional>
25 #include <string>
26 #include <type_traits>
27 #include <vector>
28 
29 // taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
30 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
31     extern "C" {
32 #endif
33 
reader_backendboost::gil::reader_backend34 #include <tiff.h>
35 #include <tiffio.h>
36 
37 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
38     }
39 #endif
40 
41 namespace boost { namespace gil {
42 
43 ///
44 /// TIFF scanline reader
45 ///
46 template< typename Device >
47 class scanline_reader< Device
48                      , tiff_tag
49                      >
50     : public reader_backend< Device
51                            , tiff_tag
52                            >
53 {
54 public:
55 
56     using tag_t = tiff_tag;
57     using backend_t = reader_backend<Device, tag_t>;
58     using this_t = scanline_reader<Device, tag_t>;
59     using iterator_t = scanline_read_iterator<this_t>;
60 
61     scanline_reader( Device&                                device
62                    , const image_read_settings< tiff_tag >& settings
63                    )
64     : backend_t( device
65                , settings
66                )
67     {
68         initialize();
69     }
70 
71     /// Read part of image defined by View and return the data.
72     void read( byte_t* dst, int pos )
73     {
74         _read_function( this, dst, pos );
75     }
76 
77     /// Skip over a scanline.
78     void skip( byte_t* dst, int pos )
79     {
80         this->_read_function( this, dst, pos );
81     }
82 
83     iterator_t begin() { return iterator_t( *this ); }
84     iterator_t end()   { return iterator_t( *this, this->_info._height ); }
85 
86 private:
87 
88     void initialize()
89     {
90         io_error_if( this->_info._is_tiled
91                    , "scanline_reader doesn't support tiled tiff images."
92                    );
93 
94         if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE )
95         {
96 
97             this->_scanline_length = this->_info._width
98                                    * num_channels< rgb16_view_t >::value
99                                    * sizeof( channel_type<rgb16_view_t>::type );
100 
101             this->_io_dev.get_field_defaulted( this->_red
102                                         , this->_green
103                                         , this->_blue
104                                         );
105 
106             _buffer = std::vector< byte_t >( this->_io_dev.get_scanline_size() );
107 
108             switch( this->_info._bits_per_sample )
109             {
110                 case 1:
111                 {
112                     using channel_t = channel_type<get_pixel_type<gray1_image_t::view_t>::type>::type;
113 
114                     int num_colors = channel_traits< channel_t >::max_value() + 1;
115 
116                     this->_palette = planar_rgb_view( num_colors
117                                               , 1
118                                               , this->_red
119                                               , this->_green
120                                               , this->_blue
121                                               , sizeof(uint16_t) * num_colors
122                                               );
123 
124                     _read_function = std::mem_fn(&this_t::read_1_bit_index_image);
125 
126                     break;
127                 }
128 
129                 case 2:
130                 {
131                     using channel_t = channel_type<get_pixel_type<gray2_image_t::view_t>::type>::type;
132 
133                     int num_colors = channel_traits< channel_t >::max_value() + 1;
134 
135                     this->_palette = planar_rgb_view( num_colors
136                                               , 1
137                                               , this->_red
138                                               , this->_green
139                                               , this->_blue
140                                               , sizeof(uint16_t) * num_colors
141                                               );
142 
143                     _read_function = std::mem_fn(&this_t::read_2_bits_index_image);
144 
145                     break;
146                 }
147                 case 4:
148                 {
149                     using channel_t = channel_type<get_pixel_type<gray4_image_t::view_t>::type>::type;
150 
151                     int num_colors = channel_traits< channel_t >::max_value() + 1;
152 
153                     this->_palette = planar_rgb_view( num_colors
154                                               , 1
155                                               , this->_red
156                                               , this->_green
157                                               , this->_blue
158                                               , sizeof(uint16_t) * num_colors
159                                               );
160 
161                     _read_function = std::mem_fn(&this_t::read_4_bits_index_image);
162 
163                     break;
164                 }
165 
166                 case 8:
167                 {
168                     using channel_t = channel_type<get_pixel_type<gray8_image_t::view_t>::type>::type;
169 
170                     int num_colors = channel_traits< channel_t >::max_value() + 1;
171 
172                     this->_palette = planar_rgb_view( num_colors
173                                               , 1
174                                               , this->_red
175                                               , this->_green
176                                               , this->_blue
177                                               , sizeof(uint16_t) * num_colors
178                                               );
179 
180                     _read_function = std::mem_fn(&this_t::read_8_bits_index_image);
181 
182                     break;
183                 }
184 
185                 case 16:
186                 {
187                     using channel_t = channel_type<get_pixel_type<gray16_image_t::view_t>::type>::type;
188 
189                     int num_colors = channel_traits< channel_t >::max_value() + 1;
190 
191                     this->_palette = planar_rgb_view( num_colors
192                                               , 1
193                                               , this->_red
194                                               , this->_green
195                                               , this->_blue
196                                               , sizeof(uint16_t) * num_colors
197                                               );
198 
199                     _read_function = std::mem_fn(&this_t::read_16_bits_index_image);
200 
201                     break;
202                 }
203 
204                 case 24:
205                 {
206                     using channel_t = channel_type<get_pixel_type<gray24_image_t::view_t>::type>::type;
207 
208                     int num_colors = channel_traits< channel_t >::max_value() + 1;
209 
210                     this->_palette = planar_rgb_view( num_colors
211                                               , 1
212                                               , this->_red
213                                               , this->_green
214                                               , this->_blue
215                                               , sizeof(uint16_t) * num_colors
216                                               );
217 
218                     _read_function = std::mem_fn(&this_t::read_24_bits_index_image);
219 
220                     break;
221                 }
222 
223                 case 32:
224                 {
225                     using channel_t = channel_type<get_pixel_type<gray32_image_t::view_t>::type>::type;
226 
227                     int num_colors = channel_traits< channel_t >::max_value() + 1;
228 
229                     this->_palette = planar_rgb_view( num_colors
230                                               , 1
231                                               , this->_red
232                                               , this->_green
233                                               , this->_blue
234                                               , sizeof(uint16_t) * num_colors
235                                               );
236 
237                     _read_function = std::mem_fn(&this_t::read_32_bits_index_image);
238 
239                     break;
240                 }
241                 default: { io_error( "Not supported palette " ); }
242             }
243         }
244         else
245         {
246             this->_scanline_length = this->_io_dev.get_scanline_size();
247 
248             if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE )
249             {
250                 io_error( "scanline_reader doesn't support planar tiff images." );
251             }
252             else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG )
253             {
254 
255                 // the read_data function needs to know what gil type the source image is
256                 // to have the default color converter function correctly
257 
258                 switch( this->_info._photometric_interpretation )
259                 {
260                     case PHOTOMETRIC_MINISWHITE:
261                     case PHOTOMETRIC_MINISBLACK:
262                     {
263                         switch( this->_info._bits_per_sample )
264                         {
265                             case  1:
266                             case  2:
267                             case  4:
268                             case  6:
269                             case  8:
270                             case 10:
271                             case 12:
272                             case 14:
273                             case 16:
274                             case 24:
275                             case 32: { _read_function = std::mem_fn(&this_t::read_row); break; }
276                             default: { io_error( "Image type is not supported." ); }
277                         }
278 
279                         break;
280                     }
281 
282                     case PHOTOMETRIC_RGB:
283                     {
284                         switch( this->_info._samples_per_pixel )
285                         {
286                             case 3:
287                             {
288                                 switch( this->_info._bits_per_sample )
289                                 {
290                                     case  2:
291                                     case  4:
292                                     case  8:
293                                     case 10:
294                                     case 12:
295                                     case 14:
296                                     case 16:
297                                     case 24:
298                                     case 32: { _read_function = std::mem_fn(&this_t::read_row);  break; }
299                                     default: { io_error( "Image type is not supported." ); }
300                                 }
301 
302                                 break;
303                             }
304 
305                             case 4:
306                             {
307                                 switch( this->_info._bits_per_sample )
308                                 {
309                                     case  2:
310                                     case  4:
311                                     case  8:
312                                     case 10:
313                                     case 12:
314                                     case 14:
315                                     case 16:
316                                     case 24:
317                                     case 32: { _read_function = std::mem_fn(&this_t::read_row);  break; }
318                                     default: { io_error( "Image type is not supported." ); }
319                                 }
320 
321                                 break;
322                             }
323 
324                             default: { io_error( "Image type is not supported." ); }
325                         }
326 
327                         break;
328                     }
329                     case PHOTOMETRIC_SEPARATED: // CYMK
330                     {
331                         switch( this->_info._bits_per_sample )
332                         {
333                             case  2:
334                             case  4:
335                             case  8:
336                             case 10:
337                             case 12:
338                             case 14:
339                             case 16:
340                             case 24:
341                             case 32: { _read_function = std::mem_fn(&this_t::read_row);  break; }
342                             default: { io_error( "Image type is not supported." ); }
343                         }
344 
345                         break;
346                     }
347 
348                     default: { io_error( "Image type is not supported." ); }
349                 }
350             }
351             else
352             {
353                 io_error( "Wrong planar configuration setting." );
354             }
355         }
356     }
357 
358     template< typename Src_View >
359     void read_n_bits_row( byte_t* dst, int pos )
360     {
361         using dst_view_t = rgb16_view_t;
362 
363         this->_io_dev.read_scanline( _buffer
364                                    , pos
365                                    , 0
366                                    );
367 
368         Src_View src_view = interleaved_view( this->_info._width
369                                             , 1
370                                             , (typename Src_View::x_iterator) &_buffer.front()
371                                             , this->_scanline_length
372                                             );
373 
374         dst_view_t dst_view = interleaved_view( this->_info._width
375                                               , 1
376                                               , (typename dst_view_t::value_type*) dst
377                                               , num_channels< dst_view_t >::value * 2 * this->_info._width
378                                               );
379 
380 
381         typename Src_View::x_iterator   src_it = src_view.row_begin( 0 );
382         typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 );
383 
384         for( dst_view_t::x_coord_t i = 0
385            ; i < this->_info._width
386            ; ++i, src_it++, dst_it++
387            )
388         {
389             auto const c = static_cast<std::uint16_t>(get_color(*src_it, gray_color_t()));
390             *dst_it = this->_palette[c];
391         }
392     }
393 
394     void read_1_bit_index_image( byte_t* dst, int pos )
395     {
396         read_n_bits_row< gray1_image_t::view_t >( dst, pos );
397     }
398 
399     void read_2_bits_index_image( byte_t* dst, int pos )
400     {
401         read_n_bits_row< gray2_image_t::view_t >( dst, pos );
402     }
403 
404     void read_4_bits_index_image( byte_t* dst, int pos )
405     {
406         read_n_bits_row< gray4_image_t::view_t >( dst, pos );
407     }
408 
409     void read_8_bits_index_image( byte_t* dst, int pos )
410     {
411         read_n_bits_row< gray8_image_t::view_t >( dst, pos );
412     }
413 
414     void read_16_bits_index_image( byte_t* dst, int pos )
415     {
416         read_n_bits_row< gray16_image_t::view_t >( dst, pos );
417     }
418 
419     void read_24_bits_index_image( byte_t* dst, int pos )
420     {
421         read_n_bits_row< gray24_image_t::view_t >( dst, pos );
422     }
423 
424     void read_32_bits_index_image( byte_t* dst, int pos )
425     {
426         read_n_bits_row< gray32_image_t::view_t >( dst, pos );
427     }
428 
429     void read_row(byte_t* dst, int pos )
430     {
431          this->_io_dev.read_scanline( dst
432                                     , pos
433                                     , 0
434                                     );
435     }
436 
437 private:
438 
439     std::vector< byte_t> _buffer;
440     detail::mirror_bits<std::vector<byte_t>, std::true_type> _mirror_bites;
441     std::function<void(this_t*, byte_t*, int)> _read_function;
442 };
443 
444 } // namespace gil
445 } // namespace boost
446 
447 #endif
448