Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-16 09:15:04

0001 //
0002 // Copyright 2008 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_BMP_DETAIL_SCANLINE_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SCANLINE_READ_HPP
0010 
0011 #include <boost/gil/extension/io/bmp/detail/is_allowed.hpp>
0012 #include <boost/gil/extension/io/bmp/detail/reader_backend.hpp>
0013 
0014 #include <boost/gil/io/base.hpp>
0015 #include <boost/gil/io/bit_operations.hpp>
0016 #include <boost/gil/io/conversion_policies.hpp>
0017 #include <boost/gil/io/device.hpp>
0018 #include <boost/gil/io/reader_base.hpp>
0019 #include <boost/gil/io/row_buffer_helper.hpp>
0020 #include <boost/gil/io/scanline_read_iterator.hpp>
0021 #include <boost/gil/io/typedefs.hpp>
0022 
0023 #include <functional>
0024 #include <type_traits>
0025 #include <vector>
0026 
0027 namespace boost { namespace gil {
0028 
0029 ///
0030 /// BMP Scanline Reader
0031 ///
0032 template< typename Device >
0033 class scanline_reader< Device
0034                      , bmp_tag
0035                      >
0036     : public reader_backend< Device
0037                            , bmp_tag
0038                            >
0039 {
0040 public:
0041 
0042     using tag_t = bmp_tag;
0043     using backend_t = reader_backend<Device, tag_t>;
0044     using this_t = scanline_reader<Device, tag_t>;
0045     using iterator_t = scanline_read_iterator<this_t>;
0046 
0047 public:
0048 
0049     //
0050     // Constructor
0051     //
0052     scanline_reader( Device&                               device
0053                    , const image_read_settings< bmp_tag >& settings
0054                    )
0055     : backend_t( device
0056                     , settings
0057                     )
0058 
0059     , _pitch( 0 )
0060     {
0061         initialize();
0062     }
0063 
0064     /// Read part of image defined by View and return the data.
0065     void read( byte_t* dst, int pos )
0066     {
0067         // jump to scanline
0068         long offset = 0;
0069 
0070         if( this->_info._height > 0 )
0071         {
0072             // the image is upside down
0073             offset = this->_info._offset
0074                    + ( this->_info._height - 1 - pos ) * this->_pitch;
0075         }
0076         else
0077         {
0078             offset = this->_info._offset
0079                    + pos * _pitch;
0080         }
0081 
0082         this->_io_dev.seek( offset );
0083 
0084 
0085         // read data
0086         _read_function(this, dst);
0087     }
0088 
0089     /// Skip over a scanline.
0090     void skip( byte_t*, int )
0091     {
0092         // nothing to do.
0093     }
0094 
0095     iterator_t begin() { return iterator_t( *this ); }
0096     iterator_t end()   { return iterator_t( *this, this->_info._height ); }
0097 
0098 private:
0099 
0100     void initialize()
0101     {
0102         if( this->_info._bits_per_pixel < 8 )
0103         {
0104             _pitch = (( this->_info._width * this->_info._bits_per_pixel ) + 7 ) >> 3;
0105         }
0106         else
0107         {
0108             _pitch = this->_info._width * (( this->_info._bits_per_pixel + 7 ) >> 3);
0109         }
0110 
0111         _pitch = (_pitch + 3) & ~3;
0112 
0113         //
0114 
0115         switch( this->_info._bits_per_pixel )
0116         {
0117             case 1:
0118             {
0119                 this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
0120 
0121                 read_palette();
0122                 _buffer.resize( _pitch );
0123 
0124                 _read_function = std::mem_fn(&this_t::read_1_bit_row);
0125 
0126                 break;
0127             }
0128 
0129             case 4:
0130             {
0131                 switch( this->_info._compression )
0132                 {
0133                     case bmp_compression::_rle4:
0134                     {
0135                         io_error( "Cannot read run-length encoded images in iterator mode. Try to read as whole image." );
0136 
0137                         break;
0138                     }
0139 
0140                     case bmp_compression::_rgb :
0141                     {
0142                         this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
0143 
0144                         read_palette();
0145                         _buffer.resize( _pitch );
0146 
0147                         _read_function = std::mem_fn(&this_t::read_4_bits_row);
0148 
0149                         break;
0150                     }
0151 
0152                     default:
0153                     {
0154                         io_error( "Unsupported compression mode in BMP file." );
0155                     }
0156                 }
0157 
0158                 break;
0159             }
0160 
0161             case 8:
0162             {
0163                 switch( this->_info._compression )
0164                 {
0165                     case bmp_compression::_rle8:
0166                     {
0167                         io_error( "Cannot read run-length encoded images in iterator mode. Try to read as whole image." );
0168 
0169                         break;
0170                     }
0171                     case bmp_compression::_rgb:
0172                     {
0173                         this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
0174 
0175                         read_palette();
0176                         _buffer.resize( _pitch );
0177 
0178                         _read_function = std::mem_fn(&this_t::read_8_bits_row);
0179 
0180                         break;
0181                     }
0182 
0183                     default: { io_error( "Unsupported compression mode in BMP file." ); break; }
0184                 }
0185 
0186                 break;
0187             }
0188 
0189             case 15:
0190             case 16:
0191             {
0192                 this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3;
0193 
0194                 _buffer.resize( _pitch );
0195 
0196                 if( this->_info._compression == bmp_compression::_bitfield )
0197                 {
0198                     this->_mask.red.mask    = this->_io_dev.read_uint32();
0199                     this->_mask.green.mask  = this->_io_dev.read_uint32();
0200                     this->_mask.blue.mask   = this->_io_dev.read_uint32();
0201 
0202                     this->_mask.red.width   = detail::count_ones( this->_mask.red.mask   );
0203                     this->_mask.green.width = detail::count_ones( this->_mask.green.mask );
0204                     this->_mask.blue.width  = detail::count_ones( this->_mask.blue.mask  );
0205 
0206                     this->_mask.red.shift   = detail::trailing_zeros( this->_mask.red.mask   );
0207                     this->_mask.green.shift = detail::trailing_zeros( this->_mask.green.mask );
0208                     this->_mask.blue.shift  = detail::trailing_zeros( this->_mask.blue.mask  );
0209                 }
0210                 else if( this->_info._compression == bmp_compression::_rgb )
0211                 {
0212                     switch( this->_info._bits_per_pixel )
0213                     {
0214                         case 15:
0215                         case 16:
0216                         {
0217                             this->_mask.red.mask   = 0x007C00; this->_mask.red.width   = 5; this->_mask.red.shift   = 10;
0218                             this->_mask.green.mask = 0x0003E0; this->_mask.green.width = 5; this->_mask.green.shift =  5;
0219                             this->_mask.blue.mask  = 0x00001F; this->_mask.blue.width  = 5; this->_mask.blue.shift  =  0;
0220 
0221                             break;
0222                         }
0223 
0224                         case 24:
0225                         case 32:
0226                         {
0227                             this->_mask.red.mask   = 0xFF0000; this->_mask.red.width   = 8; this->_mask.red.shift   = 16;
0228                             this->_mask.green.mask = 0x00FF00; this->_mask.green.width = 8; this->_mask.green.shift =  8;
0229                             this->_mask.blue.mask  = 0x0000FF; this->_mask.blue.width  = 8; this->_mask.blue.shift  =  0;
0230 
0231                             break;
0232                         }
0233                     }
0234                 }
0235                 else
0236                 {
0237                     io_error( "Unsupported BMP compression." );
0238                 }
0239 
0240 
0241                 _read_function = std::mem_fn(&this_t::read_15_bits_row);
0242 
0243                 break;
0244             }
0245 
0246             case 24:
0247             {
0248                 this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3;
0249                 _read_function = std::mem_fn(&this_t::read_row);
0250 
0251                 break;
0252             }
0253 
0254             case 32:
0255             {
0256                 this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
0257                 _read_function = std::mem_fn(&this_t::read_row);
0258 
0259                 break;
0260             }
0261 
0262             default:
0263             {
0264                 io_error( "Unsupported bits per pixel." );
0265             }
0266         }
0267     }
0268 
0269     void read_palette()
0270     {
0271         if( this->_palette.size() > 0 )
0272         {
0273             // palette has been read already.
0274             return;
0275         }
0276 
0277         int entries = this->_info._num_colors;
0278 
0279         if( entries == 0 )
0280         {
0281             entries = 1u << this->_info._bits_per_pixel;
0282         }
0283 
0284         this->_palette.resize( entries, rgba8_pixel_t(0,0,0,0) );
0285 
0286         for( int i = 0; i < entries; ++i )
0287         {
0288             get_color( this->_palette[i], blue_t()  ) = this->_io_dev.read_uint8();
0289             get_color( this->_palette[i], green_t() ) = this->_io_dev.read_uint8();
0290             get_color( this->_palette[i], red_t()   ) = this->_io_dev.read_uint8();
0291 
0292             // there are 4 entries when windows header
0293             // but 3 for os2 header
0294             if( this->_info._header_size == bmp_header_size::_win32_info_size )
0295             {
0296                 this->_io_dev.read_uint8();
0297             }
0298 
0299         } // for
0300     }
0301 
0302     template< typename View >
0303     void read_bit_row( byte_t* dst )
0304     {
0305         using src_view_t = View;
0306         using dst_view_t = rgba8_image_t::view_t;
0307 
0308         src_view_t src_view = interleaved_view( this->_info._width
0309                                               , 1
0310                                               , (typename src_view_t::x_iterator) &_buffer.front()
0311                                               , this->_pitch
0312                                               );
0313 
0314         dst_view_t dst_view = interleaved_view( this->_info._width
0315                                               , 1
0316                                               , (typename dst_view_t::value_type*) dst
0317                                               , num_channels< dst_view_t >::value * this->_info._width
0318                                               );
0319 
0320 
0321         typename src_view_t::x_iterator src_it = src_view.row_begin( 0 );
0322         typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 );
0323 
0324         for( dst_view_t::x_coord_t i = 0
0325            ; i < this->_info._width
0326            ; ++i, src_it++, dst_it++
0327            )
0328         {
0329             unsigned char c = get_color( *src_it, gray_color_t() );
0330             *dst_it = this->_palette[c];
0331         }
0332     }
0333 
0334     // Read 1 bit image. The colors are encoded by an index.
0335     void read_1_bit_row( byte_t* dst )
0336     {
0337         this->_io_dev.read( &_buffer.front(), _pitch );
0338         _mirror_bits( _buffer );
0339 
0340         read_bit_row< gray1_image_t::view_t >( dst );
0341     }
0342 
0343     // Read 4 bits image. The colors are encoded by an index.
0344     void read_4_bits_row( byte_t* dst )
0345     {
0346         this->_io_dev.read( &_buffer.front(), _pitch );
0347         _swap_half_bytes( _buffer );
0348 
0349         read_bit_row< gray4_image_t::view_t >( dst );
0350     }
0351 
0352     /// Read 8 bits image. The colors are encoded by an index.
0353     void read_8_bits_row( byte_t* dst )
0354     {
0355         this->_io_dev.read( &_buffer.front(), _pitch );
0356 
0357         read_bit_row< gray8_image_t::view_t >( dst );
0358     }
0359 
0360     /// Read 15 or 16 bits image.
0361     void read_15_bits_row( byte_t* dst )
0362     {
0363         using dst_view_t = rgb8_view_t;
0364 
0365         dst_view_t dst_view = interleaved_view( this->_info._width
0366                                               , 1
0367                                               , (typename dst_view_t::value_type*) dst
0368                                               , this->_pitch
0369                                               );
0370 
0371         typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 );
0372 
0373         //
0374         byte_t* src = &_buffer.front();
0375         this->_io_dev.read( src, _pitch );
0376 
0377         for( dst_view_t::x_coord_t i = 0
0378            ; i < this->_info._width
0379            ; ++i, src += 2
0380            )
0381         {
0382             int p = ( src[1] << 8 ) | src[0];
0383 
0384             int r = ((p & this->_mask.red.mask)   >> this->_mask.red.shift)   << (8 - this->_mask.red.width);
0385             int g = ((p & this->_mask.green.mask) >> this->_mask.green.shift) << (8 - this->_mask.green.width);
0386             int b = ((p & this->_mask.blue.mask)  >> this->_mask.blue.shift)  << (8 - this->_mask.blue.width);
0387 
0388             get_color( dst_it[i], red_t()   ) = static_cast< byte_t >( r );
0389             get_color( dst_it[i], green_t() ) = static_cast< byte_t >( g );
0390             get_color( dst_it[i], blue_t()  ) = static_cast< byte_t >( b );
0391         }
0392     }
0393 
0394     void read_row( byte_t* dst )
0395     {
0396         this->_io_dev.read( dst, _pitch );
0397     }
0398 
0399 private:
0400 
0401     // the row pitch must be multiple of 4 bytes
0402     int _pitch;
0403 
0404     std::vector<byte_t> _buffer;
0405     detail::mirror_bits <std::vector<byte_t>, std::true_type> _mirror_bits;
0406     detail::swap_half_bytes<std::vector<byte_t>, std::true_type> _swap_half_bytes;
0407 
0408     std::function<void(this_t*, byte_t*)> _read_function;
0409 };
0410 
0411 } // namespace gil
0412 } // namespace boost
0413 
0414 #endif