File indexing completed on 2025-01-18 09:36:59
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READ_HPP
0010
0011 #include <boost/gil/extension/io/targa/tags.hpp>
0012 #include <boost/gil/extension/io/targa/detail/reader_backend.hpp>
0013 #include <boost/gil/extension/io/targa/detail/is_allowed.hpp>
0014
0015 #include <boost/gil/io/detail/dynamic.hpp>
0016 #include <boost/gil/io/base.hpp>
0017 #include <boost/gil/io/bit_operations.hpp>
0018 #include <boost/gil/io/conversion_policies.hpp>
0019 #include <boost/gil/io/device.hpp>
0020 #include <boost/gil/io/reader_base.hpp>
0021 #include <boost/gil/io/row_buffer_helper.hpp>
0022 #include <boost/gil/io/typedefs.hpp>
0023
0024 #include <type_traits>
0025 #include <vector>
0026
0027 namespace boost { namespace gil {
0028
0029 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0030 #pragma warning(push)
0031 #pragma warning(disable:4512)
0032 #endif
0033
0034
0035
0036
0037 template< typename Device
0038 , typename ConversionPolicy
0039 >
0040 class reader< Device
0041 , targa_tag
0042 , ConversionPolicy
0043 >
0044 : public reader_base< targa_tag
0045 , ConversionPolicy
0046 >
0047 , public reader_backend< Device
0048 , targa_tag
0049 >
0050 {
0051 private:
0052
0053 using this_t = reader<Device, targa_tag, ConversionPolicy>;
0054 using cc_t = typename ConversionPolicy::color_converter_type;
0055
0056 public:
0057
0058 using backend_t = reader_backend<Device, targa_tag>;
0059
0060 reader( const Device& io_dev
0061 , const image_read_settings< targa_tag >& settings
0062 )
0063 : reader_base< targa_tag
0064 , ConversionPolicy
0065 >()
0066 , backend_t( io_dev
0067 , settings
0068 )
0069 {}
0070
0071 reader( const Device& io_dev
0072 , const cc_t& cc
0073 , const image_read_settings< targa_tag >& settings
0074 )
0075 : reader_base< targa_tag
0076 , ConversionPolicy
0077 >( cc )
0078 , backend_t( io_dev
0079 , settings
0080 )
0081 {}
0082
0083 template< typename View >
0084 void apply( const View& dst_view )
0085 {
0086 using is_read_and_convert_t = typename std::is_same
0087 <
0088 ConversionPolicy,
0089 detail::read_and_no_convert
0090 >::type;
0091
0092 io_error_if( !detail::is_allowed< View >( this->_info, is_read_and_convert_t() )
0093 , "Image types aren't compatible."
0094 );
0095
0096 switch( this->_info._image_type )
0097 {
0098 case targa_image_type::_rgb:
0099 {
0100 if( this->_info._color_map_type != targa_color_map_type::_rgb )
0101 {
0102 io_error( "Inconsistent color map type and image type in targa file." );
0103 }
0104
0105 if( this->_info._color_map_length != 0 )
0106 {
0107 io_error( "Non-indexed targa files containing a palette are not supported." );
0108 }
0109
0110 switch( this->_info._bits_per_pixel )
0111 {
0112 case 24:
0113 {
0114 this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 );
0115
0116 if( this->_info._screen_origin_bit )
0117 {
0118 read_data< bgr8_view_t >( flipped_up_down_view( dst_view ) );
0119 }
0120 else
0121 {
0122 read_data< bgr8_view_t >( dst_view );
0123 }
0124
0125 break;
0126 }
0127 case 32:
0128 {
0129 this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 );
0130
0131 if( this->_info._screen_origin_bit )
0132 {
0133 read_data< bgra8_view_t >( flipped_up_down_view( dst_view ) );
0134 }
0135 else
0136 {
0137 read_data< bgra8_view_t >( dst_view );
0138 }
0139
0140 break;
0141 }
0142 default:
0143 {
0144 io_error( "Unsupported bit depth in targa file." );
0145 break;
0146 }
0147 }
0148
0149 break;
0150 }
0151 case targa_image_type::_rle_rgb:
0152 {
0153 if( this->_info._color_map_type != targa_color_map_type::_rgb )
0154 {
0155 io_error( "Inconsistent color map type and image type in targa file." );
0156 }
0157
0158 if( this->_info._color_map_length != 0 )
0159 {
0160 io_error( "Non-indexed targa files containing a palette are not supported." );
0161 }
0162
0163 switch( this->_info._bits_per_pixel )
0164 {
0165 case 24:
0166 {
0167 if( this->_info._screen_origin_bit )
0168 {
0169 read_rle_data< bgr8_view_t >( flipped_up_down_view( dst_view ) );
0170 }
0171 else
0172 {
0173 read_rle_data< bgr8_view_t >( dst_view );
0174 }
0175 break;
0176 }
0177 case 32:
0178 {
0179 if( this->_info._screen_origin_bit )
0180 {
0181 read_rle_data< bgra8_view_t >( flipped_up_down_view( dst_view ) );
0182 }
0183 else
0184 {
0185 read_rle_data< bgra8_view_t >( dst_view );
0186 }
0187 break;
0188 }
0189 default:
0190 {
0191 io_error( "Unsupported bit depth in targa file." );
0192 break;
0193 }
0194 }
0195
0196 break;
0197 }
0198 default:
0199 {
0200 io_error( "Unsupported image type in targa file." );
0201 break;
0202 }
0203 }
0204 }
0205
0206 private:
0207
0208
0209
0210 template< typename View_Src, typename View_Dst >
0211 void read_data( const View_Dst& view )
0212 {
0213 byte_vector_t row( this->_info._width * (this->_info._bits_per_pixel / 8) );
0214
0215
0216 this->_io_dev.seek( static_cast< long >( this->_info._offset ));
0217
0218 View_Src v = interleaved_view( this->_info._width,
0219 1,
0220 reinterpret_cast<typename View_Src::value_type*>( &row.front() ),
0221 this->_info._width * num_channels< View_Src >::value
0222 );
0223
0224 typename View_Src::x_iterator beg = v.row_begin( 0 ) + this->_settings._top_left.x;
0225 typename View_Src::x_iterator end = beg + this->_settings._dim.x;
0226
0227
0228 for( std::ptrdiff_t y = this->_settings._dim.y - 1; y > -1; --y )
0229 {
0230
0231
0232
0233 this->_io_dev.read( &row.front(), row.size() );
0234 this->_cc_policy.read( beg, end, view.row_begin(y) );
0235 }
0236 }
0237
0238
0239
0240 template< typename View_Src, typename View_Dst >
0241 void read_rle_data( const View_Dst& view )
0242 {
0243 targa_depth::type bytes_per_pixel = this->_info._bits_per_pixel / 8;
0244 size_t image_size = this->_info._width * this->_info._height * bytes_per_pixel;
0245 byte_vector_t image_data( image_size );
0246
0247 this->_io_dev.seek( static_cast< long >( this->_info._offset ));
0248
0249 for( size_t pixel = 0; pixel < image_size; )
0250 {
0251 targa_offset::type current_byte = this->_io_dev.read_uint8();
0252
0253 if( current_byte & 0x80 )
0254 {
0255 uint8_t chunk_length = current_byte - 127;
0256 uint8_t pixel_data[4];
0257 for( size_t channel = 0; channel < bytes_per_pixel; ++channel )
0258 {
0259 pixel_data[channel] = this->_io_dev.read_uint8();
0260 }
0261
0262
0263 for( uint8_t i = 0; i < chunk_length; ++i, pixel += bytes_per_pixel )
0264 {
0265 memcpy( &image_data[pixel], pixel_data, bytes_per_pixel );
0266 }
0267 }
0268 else
0269 {
0270 uint8_t chunk_length = current_byte + 1;
0271
0272
0273 size_t pixels_written = chunk_length * bytes_per_pixel;
0274 this->_io_dev.read( &image_data[pixel], pixels_written );
0275 pixel += pixels_written;
0276 }
0277 }
0278
0279 View_Src v = flipped_up_down_view( interleaved_view( this->_info._width,
0280 this->_info._height,
0281 reinterpret_cast<typename View_Src::value_type*>( &image_data.front() ),
0282 this->_info._width * num_channels< View_Src >::value ) );
0283
0284 for( std::ptrdiff_t y = 0; y != this->_settings._dim.y; ++y )
0285 {
0286 typename View_Src::x_iterator beg = v.row_begin( y ) + this->_settings._top_left.x;
0287 typename View_Src::x_iterator end = beg + this->_settings._dim.x;
0288 this->_cc_policy.read( beg, end, view.row_begin(y) );
0289 }
0290 }
0291 };
0292
0293 namespace detail {
0294
0295 class targa_type_format_checker
0296 {
0297 public:
0298
0299 targa_type_format_checker( const targa_depth::type& bpp )
0300 : _bpp( bpp )
0301 {}
0302
0303 template< typename Image >
0304 bool apply()
0305 {
0306 if( _bpp < 32 )
0307 {
0308 return pixels_are_compatible< typename Image::value_type, rgb8_pixel_t >::value
0309 ? true
0310 : false;
0311 }
0312 else
0313 {
0314 return pixels_are_compatible< typename Image::value_type, rgba8_pixel_t >::value
0315 ? true
0316 : false;
0317 }
0318 }
0319
0320 private:
0321
0322
0323 targa_type_format_checker& operator=( const targa_type_format_checker& ) { return *this; }
0324
0325 private:
0326
0327 const targa_depth::type _bpp;
0328 };
0329
0330 struct targa_read_is_supported
0331 {
0332 template< typename View >
0333 struct apply : public is_read_supported< typename get_pixel_type< View >::type
0334 , targa_tag
0335 >
0336 {};
0337 };
0338
0339 }
0340
0341
0342
0343
0344 template< typename Device >
0345 class dynamic_image_reader< Device
0346 , targa_tag
0347 >
0348 : public reader< Device
0349 , targa_tag
0350 , detail::read_and_no_convert
0351 >
0352 {
0353 using parent_t = reader<Device, targa_tag, detail::read_and_no_convert>;
0354
0355 public:
0356
0357 dynamic_image_reader( const Device& io_dev
0358 , const image_read_settings< targa_tag >& settings
0359 )
0360 : parent_t( io_dev
0361 , settings
0362 )
0363 {}
0364
0365 template< typename ...Images >
0366 void apply( any_image< Images... >& images )
0367 {
0368 detail::targa_type_format_checker format_checker( this->_info._bits_per_pixel );
0369
0370 if( !detail::construct_matched( images
0371 , format_checker
0372 ))
0373 {
0374 io_error( "No matching image type between those of the given any_image and that of the file" );
0375 }
0376 else
0377 {
0378 this->init_image( images
0379 , this->_settings
0380 );
0381
0382 detail::dynamic_io_fnobj< detail::targa_read_is_supported
0383 , parent_t
0384 > op( this );
0385
0386 variant2::visit( op
0387 ,view( images )
0388 );
0389 }
0390 }
0391 };
0392
0393 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0394 #pragma warning(pop)
0395 #endif
0396
0397 }
0398 }
0399
0400 #endif