Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:59

0001 //
0002 // Copyright 2012 Kenneth Riddile, Christian Henning
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
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) //assignment operator could not be generated
0032 #endif
0033 
0034 ///
0035 /// Targa Reader
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     // 8-8-8 BGR
0209     // 8-8-8-8 BGRA
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         // jump to first scanline
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         // read bottom up since targa origin is bottom left
0228         for( std::ptrdiff_t y = this->_settings._dim.y - 1; y > -1; --y )
0229         {
0230             // @todo: For now we're reading the whole scanline which is
0231             // slightly inefficient. Later versions should try to read
0232             // only the bytes which are necessary.
0233             this->_io_dev.read( &row.front(), row.size() );
0234             this->_cc_policy.read( beg, end, view.row_begin(y) );
0235         }
0236     }
0237 
0238     // 8-8-8 BGR
0239     // 8-8-8-8 BGRA
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 ) // run length chunk (high bit = 1)
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                 // Repeat the next pixel chunk_length times
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 // raw chunk
0269             {
0270                 uint8_t chunk_length = current_byte + 1;
0271 
0272                 // Write the next chunk_length pixels directly
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     // to avoid C4512
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 } // namespace detail
0340 
0341 ///
0342 /// Targa Dynamic Image Reader
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 } // namespace gil
0398 } // namespace boost
0399 
0400 #endif