File indexing completed on 2024-11-16 09:15:04
0001
0002
0003
0004
0005
0006
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
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
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
0065 void read( byte_t* dst, int pos )
0066 {
0067
0068 long offset = 0;
0069
0070 if( this->_info._height > 0 )
0071 {
0072
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
0086 _read_function(this, dst);
0087 }
0088
0089
0090 void skip( byte_t*, int )
0091 {
0092
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
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
0293
0294 if( this->_info._header_size == bmp_header_size::_win32_info_size )
0295 {
0296 this->_io_dev.read_uint8();
0297 }
0298
0299 }
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
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
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
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
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
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 }
0412 }
0413
0414 #endif