]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/extension/io/pnm/detail/read.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / 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