File indexing completed on 2025-01-18 09:36:58
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
0010
0011 #include <boost/gil/extension/io/pnm/tags.hpp>
0012 #include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
0013 #include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
0014
0015 #include <boost/gil.hpp> // FIXME: Include what you use!
0016 #include <boost/gil/io/detail/dynamic.hpp>
0017 #include <boost/gil/io/base.hpp>
0018 #include <boost/gil/io/bit_operations.hpp>
0019 #include <boost/gil/io/conversion_policies.hpp>
0020 #include <boost/gil/io/device.hpp>
0021 #include <boost/gil/io/reader_base.hpp>
0022 #include <boost/gil/io/row_buffer_helper.hpp>
0023 #include <boost/gil/io/typedefs.hpp>
0024
0025 #include <type_traits>
0026 #include <vector>
0027
0028 namespace boost { namespace gil {
0029
0030 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0031 #pragma warning(push)
0032 #pragma warning(disable:4512)
0033 #endif
0034
0035
0036
0037
0038 template< typename Device
0039 , typename ConversionPolicy
0040 >
0041 class reader< Device
0042 , pnm_tag
0043 , ConversionPolicy
0044 >
0045 : public reader_base< pnm_tag
0046 , ConversionPolicy
0047 >
0048 , public reader_backend< Device
0049 , pnm_tag
0050 >
0051 {
0052
0053 private:
0054
0055 using this_t = reader<Device, pnm_tag, ConversionPolicy>;
0056 using cc_t = typename ConversionPolicy::color_converter_type;
0057
0058 public:
0059
0060 using backend_t = reader_backend<Device, pnm_tag>;
0061
0062 reader( const Device& io_dev
0063 , const image_read_settings< pnm_tag >& settings
0064 )
0065 : reader_base< pnm_tag
0066 , ConversionPolicy
0067 >()
0068 , backend_t( io_dev
0069 , settings
0070 )
0071 {}
0072
0073 reader( const Device& io_dev
0074 , const cc_t& cc
0075 , const image_read_settings< pnm_tag >& settings
0076 )
0077 : reader_base< pnm_tag
0078 , ConversionPolicy
0079 >( cc )
0080 , backend_t( io_dev
0081 , settings
0082 )
0083 {}
0084
0085 template<typename View>
0086 void apply( const View& view )
0087 {
0088 using is_read_and_convert_t = typename std::is_same
0089 <
0090 ConversionPolicy,
0091 detail::read_and_no_convert
0092 >::type;
0093
0094 io_error_if( !detail::is_allowed< View >( this->_info
0095 , is_read_and_convert_t()
0096 )
0097 , "Image types aren't compatible."
0098 );
0099
0100 switch( this->_info._type )
0101 {
0102
0103 case pnm_image_type::mono_asc_t::value:
0104 case pnm_image_type::gray_asc_t::value:
0105 {
0106 this->_scanline_length = this->_info._width;
0107
0108 read_text_data< gray8_view_t >( view );
0109
0110 break;
0111 }
0112
0113 case pnm_image_type::color_asc_t::value:
0114 {
0115 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
0116
0117 read_text_data< rgb8_view_t >( view );
0118
0119 break;
0120 }
0121
0122 case pnm_image_type::mono_bin_t::value:
0123 {
0124
0125 this->_scanline_length = ( this->_info._width + 7 ) >> 3;
0126
0127 read_bin_data< gray1_image_t::view_t >( view );
0128
0129 break;
0130 }
0131
0132 case pnm_image_type::gray_bin_t::value:
0133 {
0134
0135 this->_scanline_length = this->_info._width;
0136
0137 read_bin_data< gray8_view_t >( view );
0138
0139 break;
0140 }
0141
0142 case pnm_image_type::color_bin_t::value:
0143 {
0144
0145 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
0146
0147 read_bin_data< rgb8_view_t >( view );
0148 break;
0149 }
0150 }
0151 }
0152
0153 private:
0154
0155 template< typename View_Src
0156 , typename View_Dst
0157 >
0158 void read_text_data( const View_Dst& dst )
0159 {
0160 using y_t = typename View_Dst::y_coord_t;
0161
0162 byte_vector_t row( this->_scanline_length );
0163
0164
0165 for( int y = 0; y < this->_settings._top_left.y; ++y )
0166 {
0167 read_text_row< View_Src >( dst, row, y, false );
0168 }
0169
0170 for( y_t y = 0; y < dst.height(); ++y )
0171 {
0172 read_text_row< View_Src >( dst, row, y, true );
0173 }
0174 }
0175
0176 template< typename View_Src
0177 , typename View_Dst
0178 >
0179 void read_text_row( const View_Dst& dst
0180 , byte_vector_t& row
0181 , typename View_Dst::y_coord_t y
0182 , bool process
0183 )
0184 {
0185 View_Src src = interleaved_view( this->_info._width
0186 , 1
0187 , (typename View_Src::value_type*) &row.front()
0188 , this->_scanline_length
0189 );
0190
0191 for( uint32_t x = 0; x < this->_scanline_length; ++x )
0192 {
0193 for( uint32_t k = 0; ; )
0194 {
0195 int ch = this->_io_dev.getc_unchecked();
0196
0197 if( isdigit( ch ))
0198 {
0199 buf[ k++ ] = static_cast< char >( ch );
0200 }
0201 else if( k )
0202 {
0203 buf[ k ] = 0;
0204 break;
0205 }
0206 else if( ch == EOF || !isspace( ch ))
0207 {
0208 return;
0209 }
0210 }
0211
0212 if( process )
0213 {
0214 int value = atoi( buf );
0215
0216 if( this->_info._max_value == 1 )
0217 {
0218 using channel_t = typename channel_type<typename get_pixel_type<View_Dst>::type>::type;
0219
0220
0221 row[x] = ( value != 0 )
0222 ? typename channel_traits< channel_t >::value_type( 0 )
0223 : channel_traits< channel_t >::max_value();
0224 }
0225 else
0226 {
0227 row[x] = static_cast< byte_t >( value );
0228 }
0229 }
0230 }
0231
0232 if( process )
0233 {
0234
0235
0236 copy_data< View_Dst
0237 , View_Src >( dst
0238 , src
0239 , y
0240 , typename std::is_same< View_Dst
0241 , gray1_image_t::view_t
0242 >::type()
0243 );
0244 }
0245 }
0246
0247 template< typename View_Dst
0248 , typename View_Src
0249 >
0250 void copy_data( const View_Dst& dst
0251 , const View_Src& src
0252 , typename View_Dst::y_coord_t y
0253 , std::true_type
0254 )
0255 {
0256 if( this->_info._max_value == 1 )
0257 {
0258 typename View_Dst::x_iterator it = dst.row_begin( y );
0259
0260 for( typename View_Dst::x_coord_t x = 0
0261 ; x < dst.width()
0262 ; ++x
0263 )
0264 {
0265 it[x] = src[x];
0266 }
0267 }
0268 else
0269 {
0270 copy_data(dst, src, y, std::false_type{});
0271 }
0272 }
0273
0274 template< typename View_Dst
0275 , typename View_Src
0276 >
0277 void copy_data( const View_Dst& view
0278 , const View_Src& src
0279 , typename View_Dst::y_coord_t y
0280 , std::false_type
0281 )
0282 {
0283 typename View_Src::x_iterator beg = src.row_begin( 0 ) + this->_settings._top_left.x;
0284 typename View_Src::x_iterator end = beg + this->_settings._dim.x;
0285
0286 this->_cc_policy.read( beg
0287 , end
0288 , view.row_begin( y )
0289 );
0290 }
0291
0292
0293 template< typename View_Src
0294 , typename View_Dst
0295 >
0296 void read_bin_data( const View_Dst& view )
0297 {
0298 using y_t = typename View_Dst::y_coord_t;
0299 using is_bit_aligned_t = typename is_bit_aligned<typename View_Src::value_type>::type;
0300
0301 using rh_t = detail::row_buffer_helper_view<View_Src>;
0302 rh_t rh( this->_scanline_length, true );
0303
0304 typename rh_t::iterator_t beg = rh.begin() + this->_settings._top_left.x;
0305 typename rh_t::iterator_t end = beg + this->_settings._dim.x;
0306
0307
0308
0309 detail::negate_bits
0310 <
0311 typename rh_t::buffer_t,
0312 std::integral_constant<bool, is_bit_aligned_t::value>
0313 > neg;
0314
0315 detail::swap_half_bytes
0316 <
0317 typename rh_t::buffer_t,
0318 std::integral_constant<bool, is_bit_aligned_t::value>
0319 > swhb;
0320
0321
0322 for( y_t y = 0; y < this->_settings._top_left.y; ++y )
0323 {
0324 this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
0325 , this->_scanline_length
0326 );
0327 }
0328
0329 for( y_t y = 0; y < view.height(); ++y )
0330 {
0331 this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
0332 , this->_scanline_length
0333 );
0334
0335 neg( rh.buffer() );
0336 swhb( rh.buffer() );
0337
0338 this->_cc_policy.read( beg
0339 , end
0340 , view.row_begin( y )
0341 );
0342 }
0343 }
0344
0345 private:
0346
0347 char buf[16];
0348
0349 };
0350
0351
0352 namespace detail {
0353
0354 struct pnm_type_format_checker
0355 {
0356 pnm_type_format_checker( pnm_image_type::type type )
0357 : _type( type )
0358 {}
0359
0360 template< typename Image >
0361 bool apply()
0362 {
0363 using is_supported_t = is_read_supported
0364 <
0365 typename get_pixel_type<typename Image::view_t>::type,
0366 pnm_tag
0367 >;
0368
0369 return is_supported_t::_asc_type == _type
0370 || is_supported_t::_bin_type == _type;
0371 }
0372
0373 private:
0374
0375 pnm_image_type::type _type;
0376 };
0377
0378 struct pnm_read_is_supported
0379 {
0380 template< typename View >
0381 struct apply : public is_read_supported< typename get_pixel_type< View >::type
0382 , pnm_tag
0383 >
0384 {};
0385 };
0386
0387 }
0388
0389
0390
0391
0392 template< typename Device
0393 >
0394 class dynamic_image_reader< Device
0395 , pnm_tag
0396 >
0397 : public reader< Device
0398 , pnm_tag
0399 , detail::read_and_no_convert
0400 >
0401 {
0402 using parent_t = reader
0403 <
0404 Device,
0405 pnm_tag,
0406 detail::read_and_no_convert
0407 >;
0408
0409 public:
0410
0411 dynamic_image_reader( const Device& io_dev
0412 , const image_read_settings< pnm_tag >& settings
0413 )
0414 : parent_t( io_dev
0415 , settings
0416 )
0417 {}
0418
0419 template< typename ...Images >
0420 void apply( any_image< Images... >& images )
0421 {
0422 detail::pnm_type_format_checker format_checker( this->_info._type );
0423
0424 if( !detail::construct_matched( images
0425 , format_checker
0426 ))
0427 {
0428 io_error( "No matching image type between those of the given any_image and that of the file" );
0429 }
0430 else
0431 {
0432 this->init_image( images
0433 , this->_settings
0434 );
0435
0436 detail::dynamic_io_fnobj< detail::pnm_read_is_supported
0437 , parent_t
0438 > op( this );
0439
0440 variant2::visit( op
0441 ,view( images )
0442 );
0443 }
0444 }
0445 };
0446
0447 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0448 #pragma warning(pop)
0449 #endif
0450
0451 }
0452 }
0453
0454 #endif