Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / io / pnm / detail / read.hpp
1 //
2 // Copyright 2012 Christian Henning
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_PNM_DETAIL_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
10
11 #include <boost/gil/extension/io/pnm/tags.hpp>
12 #include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
13 #include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
14
15 #include <boost/gil.hpp> // FIXME: Include what you use!
16 #include <boost/gil/io/base.hpp>
17 #include <boost/gil/io/bit_operations.hpp>
18 #include <boost/gil/io/conversion_policies.hpp>
19 #include <boost/gil/io/device.hpp>
20 #include <boost/gil/io/dynamic_io_new.hpp>
21 #include <boost/gil/io/reader_base.hpp>
22 #include <boost/gil/io/row_buffer_helper.hpp>
23 #include <boost/gil/io/typedefs.hpp>
24
25 #include <type_traits>
26 #include <vector>
27
28 namespace boost { namespace gil {
29
30 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
31 #pragma warning(push)
32 #pragma warning(disable:4512) //assignment operator could not be generated
33 #endif
34
35 ///
36 /// PNM Reader
37 ///
38 template< typename Device
39         , typename ConversionPolicy
40         >
41 class reader< Device
42             , pnm_tag
43             , ConversionPolicy
44             >
45     : public reader_base< pnm_tag
46                         , ConversionPolicy
47                         >
48     , public reader_backend< Device
49                            , pnm_tag
50                            >
51 {
52
53 private:
54
55     using this_t = reader<Device, pnm_tag, ConversionPolicy>;
56     using cc_t = typename ConversionPolicy::color_converter_type;
57
58 public:
59
60     using backend_t = reader_backend<Device, pnm_tag>;
61
62     reader( const Device&                         io_dev
63           , const image_read_settings< pnm_tag >& settings
64           )
65     : reader_base< pnm_tag
66                  , ConversionPolicy
67                  >()
68     , backend_t( io_dev
69                , settings
70                )
71     {}
72
73     reader( const Device&                         io_dev
74           , const cc_t&                           cc
75           , const image_read_settings< pnm_tag >& settings
76           )
77     : reader_base< pnm_tag
78                  , ConversionPolicy
79                  >( cc )
80     , backend_t( io_dev
81                , settings
82                )
83     {}
84
85     template<typename View>
86     void apply( const View& view )
87     {
88         using is_read_and_convert_t = typename std::is_same
89             <
90                 ConversionPolicy,
91                 detail::read_and_no_convert
92             >::type;
93
94         io_error_if( !detail::is_allowed< View >( this->_info
95                                                 , is_read_and_convert_t()
96                                                 )
97                    , "Image types aren't compatible."
98                    );
99
100         switch( this->_info._type )
101         {
102             // reading mono text is reading grayscale but with only two values
103             case pnm_image_type::mono_asc_t::value:
104             case pnm_image_type::gray_asc_t::value:
105             {
106                 this->_scanline_length = this->_info._width;
107
108                 read_text_data< gray8_view_t >( view );
109
110                 break;
111             }
112
113             case pnm_image_type::color_asc_t::value:
114             {
115                 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
116
117                 read_text_data< rgb8_view_t  >( view );
118
119                 break;
120             }
121
122             case pnm_image_type::mono_bin_t::value:
123             {
124                 //gray1_image_t
125                 this->_scanline_length = ( this->_info._width + 7 ) >> 3;
126
127                 read_bin_data< gray1_image_t::view_t >( view );
128
129                 break;
130             }
131
132             case pnm_image_type::gray_bin_t::value:
133             {
134                 // gray8_image_t
135                 this->_scanline_length = this->_info._width;
136
137                 read_bin_data< gray8_view_t >( view );
138
139                 break;
140             }
141
142             case pnm_image_type::color_bin_t::value:
143             {
144                 // rgb8_image_t
145                 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
146
147                 read_bin_data< rgb8_view_t >( view );
148                 break;
149             }
150         }
151     }
152
153 private:
154
155     template< typename View_Src
156             , typename View_Dst
157             >
158     void read_text_data( const View_Dst& dst )
159     {
160         using y_t = typename View_Dst::y_coord_t;
161
162         byte_vector_t row( this->_scanline_length );
163
164         //Skip scanlines if necessary.
165         for( int y = 0; y <  this->_settings._top_left.y; ++y )
166         {
167             read_text_row< View_Src >( dst, row, y, false );
168         }
169
170         for( y_t y = 0; y < dst.height(); ++y )
171         {
172             read_text_row< View_Src >( dst, row, y, true );
173         }
174     }
175
176     template< typename View_Src
177             , typename View_Dst
178             >
179     void read_text_row( const View_Dst&              dst
180                       , byte_vector_t&               row
181                       , typename View_Dst::y_coord_t y
182                       , bool                         process
183                       )
184     {
185         View_Src src = interleaved_view( this->_info._width
186                                        , 1
187                                        , (typename View_Src::value_type*) &row.front()
188                                        , this->_scanline_length
189                                        );
190
191         for( uint32_t x = 0; x < this->_scanline_length; ++x )
192         {
193             for( uint32_t k = 0; ; )
194             {
195                 int ch = this->_io_dev.getc_unchecked();
196
197                 if( isdigit( ch ))
198                 {
199                     buf[ k++ ] = static_cast< char >( ch );
200                 }
201                 else if( k )
202                 {
203                     buf[ k ] = 0;
204                     break;
205                 }
206                 else if( ch == EOF || !isspace( ch ))
207                 {
208                     return;
209                 }
210             }
211
212             if( process )
213             {
214                 int value = atoi( buf );
215
216                 if( this->_info._max_value == 1 )
217                 {
218                     using channel_t = typename channel_type<typename get_pixel_type<View_Dst>::type>::type;
219
220                     // for pnm format 0 is white
221                     row[x] = ( value != 0 )
222                              ? typename channel_traits< channel_t >::value_type( 0 )
223                              : channel_traits< channel_t >::max_value();
224                 }
225                 else
226                 {
227                     row[x] = static_cast< byte_t >( value );
228                 }
229             }
230         }
231
232         if( process )
233         {
234             // We are reading a gray1_image like a gray8_image but the two pixel_t
235             // aren't compatible. Though, read_and_no_convert::read(...) wont work.
236             copy_data< View_Dst
237                      , View_Src >( dst
238                                  , src
239                                  , y
240                                  , typename std::is_same< View_Dst
241                                                    , gray1_image_t::view_t
242                                                    >::type()
243                                  );
244         }
245     }
246
247     template< typename View_Dst
248             , typename View_Src
249             >
250     void copy_data( const View_Dst&              dst
251                   , const View_Src&              src
252                   , typename View_Dst::y_coord_t y
253                   , std::true_type // is gray1_view
254                   )
255     {
256         if(  this->_info._max_value == 1 )
257         {
258             typename View_Dst::x_iterator it = dst.row_begin( y );
259
260             for( typename View_Dst::x_coord_t x = 0
261                ; x < dst.width()
262                ; ++x
263                )
264             {
265                 it[x] = src[x];
266             }
267         }
268         else
269         {
270             copy_data(dst, src, y, std::false_type{});
271         }
272     }
273
274     template< typename View_Dst
275             , typename View_Src
276             >
277     void copy_data( const View_Dst&              view
278                   , const View_Src&              src
279                   , typename View_Dst::y_coord_t y
280                   , std::false_type // is gray1_view
281                   )
282     {
283         typename View_Src::x_iterator beg = src.row_begin( 0 ) + this->_settings._top_left.x;
284         typename View_Src::x_iterator end = beg + this->_settings._dim.x;
285
286         this->_cc_policy.read( beg
287                              , end
288                              , view.row_begin( y )
289                              );
290     }
291
292
293     template< typename View_Src
294             , typename View_Dst
295             >
296     void read_bin_data( const View_Dst& view )
297     {
298         using y_t = typename View_Dst::y_coord_t;
299         using is_bit_aligned_t = typename is_bit_aligned<typename View_Src::value_type>::type;
300
301         using rh_t = detail::row_buffer_helper_view<View_Src>;
302         rh_t rh( this->_scanline_length, true );
303
304         typename rh_t::iterator_t beg = rh.begin() + this->_settings._top_left.x;
305         typename rh_t::iterator_t end = beg + this->_settings._dim.x;
306
307         // For bit_aligned images we need to negate all bytes in the row_buffer
308         // to make sure that 0 is black and 255 is white.
309         detail::negate_bits
310             <
311                 typename rh_t::buffer_t,
312                 std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
313             > neg;
314
315         detail::swap_half_bytes
316             <
317                 typename rh_t::buffer_t,
318                 std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
319             > swhb;
320
321         //Skip scanlines if necessary.
322         for( y_t y = 0; y < this->_settings._top_left.y; ++y )
323         {
324             this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
325                         , this->_scanline_length
326                         );
327         }
328
329         for( y_t y = 0; y < view.height(); ++y )
330         {
331             this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
332                         , this->_scanline_length
333                         );
334
335             neg( rh.buffer() );
336             swhb( rh.buffer() );
337
338             this->_cc_policy.read( beg
339                                  , end
340                                  , view.row_begin( y )
341                                  );
342         }
343     }
344
345 private:
346
347     char buf[16];
348
349 };
350
351
352 namespace detail {
353
354 struct pnm_type_format_checker
355 {
356     pnm_type_format_checker( pnm_image_type::type type )
357     : _type( type )
358     {}
359
360     template< typename Image >
361     bool apply()
362     {
363         using is_supported_t = is_read_supported
364             <
365                 typename get_pixel_type<typename Image::view_t>::type,
366                 pnm_tag
367             >;
368
369         return is_supported_t::_asc_type == _type
370             || is_supported_t::_bin_type == _type;
371     }
372
373 private:
374
375     pnm_image_type::type _type;
376 };
377
378 struct pnm_read_is_supported
379 {
380     template< typename View >
381     struct apply : public is_read_supported< typename get_pixel_type< View >::type
382                                            , pnm_tag
383                                            >
384     {};
385 };
386
387 } // namespace detail
388
389 ///
390 /// PNM Dynamic Image Reader
391 ///
392 template< typename Device
393         >
394 class dynamic_image_reader< Device
395                           , pnm_tag
396                           >
397     : public reader< Device
398                    , pnm_tag
399                    , detail::read_and_no_convert
400                    >
401 {
402     using parent_t = reader
403         <
404             Device,
405             pnm_tag,
406             detail::read_and_no_convert
407         >;
408
409 public:
410
411     dynamic_image_reader( const Device&                         io_dev
412                         , const image_read_settings< pnm_tag >& settings
413                         )
414     : parent_t( io_dev
415               , settings
416               )
417     {}
418
419     template< typename Images >
420     void apply( any_image< Images >& images )
421     {
422         detail::pnm_type_format_checker format_checker( this->_info._type );
423
424         if( !construct_matched( images
425                               , format_checker
426                               ))
427         {
428             io_error( "No matching image type between those of the given any_image and that of the file" );
429         }
430         else
431         {
432             this->init_image( images
433                             , this->_settings
434                             );
435
436             detail::dynamic_io_fnobj< detail::pnm_read_is_supported
437                                     , parent_t
438                                     > op( this );
439
440             apply_operation( view( images )
441                            , op
442                            );
443         }
444     }
445 };
446
447 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
448 #pragma warning(pop)
449 #endif
450
451 } // gil
452 } // boost
453
454 #endif