1 //
2 // Copyright 2008 Christian Henning
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SCANLINE_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SCANLINE_READ_HPP
10 
11 #include <boost/gil/extension/io/bmp/detail/is_allowed.hpp>
12 #include <boost/gil/extension/io/bmp/detail/reader_backend.hpp>
13 
14 #include <boost/gil/io/base.hpp>
15 #include <boost/gil/io/bit_operations.hpp>
16 #include <boost/gil/io/conversion_policies.hpp>
17 #include <boost/gil/io/device.hpp>
18 #include <boost/gil/io/reader_base.hpp>
19 #include <boost/gil/io/row_buffer_helper.hpp>
20 #include <boost/gil/io/scanline_read_iterator.hpp>
21 #include <boost/gil/io/typedefs.hpp>
22 
23 #include <functional>
24 #include <type_traits>
25 #include <vector>
26 
27 namespace boost { namespace gil {
28 
29 ///
30 /// BMP Scanline Reader
31 ///
32 template< typename Device >
33 class scanline_reader< Device
34                      , bmp_tag
35                      >
36     : public reader_backend< Device
37                            , bmp_tag
38                            >
39 {
40 public:
41 
42     using tag_t = bmp_tag;
43     using backend_t = reader_backend<Device, tag_t>;
44     using this_t = scanline_reader<Device, tag_t>;
45     using iterator_t = scanline_read_iterator<this_t>;
46 
47 public:
48 
49     //
50     // Constructor
51     //
scanline_reader(Device & device,const image_read_settings<bmp_tag> & settings)52     scanline_reader( Device&                               device
53                    , const image_read_settings< bmp_tag >& settings
54                    )
55     : backend_t( device
56                     , settings
57                     )
58 
59     , _pitch( 0 )
60     {
61         initialize();
62     }
63 
64     /// Read part of image defined by View and return the data.
read(byte_t * dst,int pos)65     void read( byte_t* dst, int pos )
66     {
67         // jump to scanline
68         long offset = 0;
69 
70         if( this->_info._height > 0 )
71         {
72             // the image is upside down
73             offset = this->_info._offset
74                    + ( this->_info._height - 1 - pos ) * this->_pitch;
75         }
76         else
77         {
78             offset = this->_info._offset
79                    + pos * _pitch;
80         }
81 
82         this->_io_dev.seek( offset );
83 
84 
85         // read data
86         _read_function(this, dst);
87     }
88 
89     /// Skip over a scanline.
skip(byte_t *,int)90     void skip( byte_t*, int )
91     {
92         // nothing to do.
93     }
94 
begin()95     iterator_t begin() { return iterator_t( *this ); }
end()96     iterator_t end()   { return iterator_t( *this, this->_info._height ); }
97 
98 private:
99 
initialize()100     void initialize()
101     {
102         if( this->_info._bits_per_pixel < 8 )
103         {
104             _pitch = (( this->_info._width * this->_info._bits_per_pixel ) + 7 ) >> 3;
105         }
106         else
107         {
108             _pitch = this->_info._width * (( this->_info._bits_per_pixel + 7 ) >> 3);
109         }
110 
111         _pitch = (_pitch + 3) & ~3;
112 
113         //
114 
115         switch( this->_info._bits_per_pixel )
116         {
117             case 1:
118             {
119                 this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
120 
121                 read_palette();
122                 _buffer.resize( _pitch );
123 
124                 _read_function = std::mem_fn(&this_t::read_1_bit_row);
125 
126                 break;
127             }
128 
129             case 4:
130             {
131                 switch( this->_info._compression )
132                 {
133                     case bmp_compression::_rle4:
134                     {
135                         io_error( "Cannot read run-length encoded images in iterator mode. Try to read as whole image." );
136 
137                         break;
138                     }
139 
140                     case bmp_compression::_rgb :
141                     {
142                         this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
143 
144                         read_palette();
145                         _buffer.resize( _pitch );
146 
147                         _read_function = std::mem_fn(&this_t::read_4_bits_row);
148 
149                         break;
150                     }
151 
152                     default:
153                     {
154                         io_error( "Unsupported compression mode in BMP file." );
155                     }
156                 }
157 
158                 break;
159             }
160 
161             case 8:
162             {
163                 switch( this->_info._compression )
164                 {
165                     case bmp_compression::_rle8:
166                     {
167                         io_error( "Cannot read run-length encoded images in iterator mode. Try to read as whole image." );
168 
169                         break;
170                     }
171                     case bmp_compression::_rgb:
172                     {
173                         this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
174 
175                         read_palette();
176                         _buffer.resize( _pitch );
177 
178                         _read_function = std::mem_fn(&this_t::read_8_bits_row);
179 
180                         break;
181                     }
182 
183                     default: { io_error( "Unsupported compression mode in BMP file." ); break; }
184                 }
185 
186                 break;
187             }
188 
189             case 15:
190             case 16:
191             {
192                 this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3;
193 
194                 _buffer.resize( _pitch );
195 
196                 if( this->_info._compression == bmp_compression::_bitfield )
197                 {
198                     this->_mask.red.mask    = this->_io_dev.read_uint32();
199                     this->_mask.green.mask  = this->_io_dev.read_uint32();
200                     this->_mask.blue.mask   = this->_io_dev.read_uint32();
201 
202                     this->_mask.red.width   = detail::count_ones( this->_mask.red.mask   );
203                     this->_mask.green.width = detail::count_ones( this->_mask.green.mask );
204                     this->_mask.blue.width  = detail::count_ones( this->_mask.blue.mask  );
205 
206                     this->_mask.red.shift   = detail::trailing_zeros( this->_mask.red.mask   );
207                     this->_mask.green.shift = detail::trailing_zeros( this->_mask.green.mask );
208                     this->_mask.blue.shift  = detail::trailing_zeros( this->_mask.blue.mask  );
209                 }
210                 else if( this->_info._compression == bmp_compression::_rgb )
211                 {
212                     switch( this->_info._bits_per_pixel )
213                     {
214                         case 15:
215                         case 16:
216                         {
217                             this->_mask.red.mask   = 0x007C00; this->_mask.red.width   = 5; this->_mask.red.shift   = 10;
218                             this->_mask.green.mask = 0x0003E0; this->_mask.green.width = 5; this->_mask.green.shift =  5;
219                             this->_mask.blue.mask  = 0x00001F; this->_mask.blue.width  = 5; this->_mask.blue.shift  =  0;
220 
221                             break;
222                         }
223 
224                         case 24:
225                         case 32:
226                         {
227                             this->_mask.red.mask   = 0xFF0000; this->_mask.red.width   = 8; this->_mask.red.shift   = 16;
228                             this->_mask.green.mask = 0x00FF00; this->_mask.green.width = 8; this->_mask.green.shift =  8;
229                             this->_mask.blue.mask  = 0x0000FF; this->_mask.blue.width  = 8; this->_mask.blue.shift  =  0;
230 
231                             break;
232                         }
233                     }
234                 }
235                 else
236                 {
237                     io_error( "Unsupported BMP compression." );
238                 }
239 
240 
241                 _read_function = std::mem_fn(&this_t::read_15_bits_row);
242 
243                 break;
244             }
245 
246             case 24:
247             {
248                 this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3;
249                 _read_function = std::mem_fn(&this_t::read_row);
250 
251                 break;
252             }
253 
254             case 32:
255             {
256                 this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3;
257                 _read_function = std::mem_fn(&this_t::read_row);
258 
259                 break;
260             }
261 
262             default:
263             {
264                 io_error( "Unsupported bits per pixel." );
265             }
266         }
267     }
268 
read_palette()269     void read_palette()
270     {
271         if( this->_palette.size() > 0 )
272         {
273             // palette has been read already.
274             return;
275         }
276 
277         int entries = this->_info._num_colors;
278 
279         if( entries == 0 )
280         {
281             entries = 1u << this->_info._bits_per_pixel;
282         }
283 
284 		this->_palette.resize( entries, rgba8_pixel_t(0,0,0,0) );
285 
286         for( int i = 0; i < entries; ++i )
287         {
288             get_color( this->_palette[i], blue_t()  ) = this->_io_dev.read_uint8();
289             get_color( this->_palette[i], green_t() ) = this->_io_dev.read_uint8();
290             get_color( this->_palette[i], red_t()   ) = this->_io_dev.read_uint8();
291 
292             // there are 4 entries when windows header
293             // but 3 for os2 header
294             if( this->_info._header_size == bmp_header_size::_win32_info_size )
295             {
296                 this->_io_dev.read_uint8();
297             }
298 
299         } // for
300     }
301 
302     template< typename View >
read_bit_row(byte_t * dst)303     void read_bit_row( byte_t* dst )
304     {
305         using src_view_t = View;
306         using dst_view_t = rgba8_image_t::view_t;
307 
308         src_view_t src_view = interleaved_view( this->_info._width
309                                               , 1
310                                               , (typename src_view_t::x_iterator) &_buffer.front()
311                                               , this->_pitch
312                                               );
313 
314         dst_view_t dst_view = interleaved_view( this->_info._width
315                                               , 1
316                                               , (typename dst_view_t::value_type*) dst
317                                               , num_channels< dst_view_t >::value * this->_info._width
318                                               );
319 
320 
321         typename src_view_t::x_iterator src_it = src_view.row_begin( 0 );
322         typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 );
323 
324         for( dst_view_t::x_coord_t i = 0
325            ; i < this->_info._width
326            ; ++i, src_it++, dst_it++
327            )
328         {
329             unsigned char c = get_color( *src_it, gray_color_t() );
330             *dst_it = this->_palette[c];
331         }
332     }
333 
334     // Read 1 bit image. The colors are encoded by an index.
read_1_bit_row(byte_t * dst)335     void read_1_bit_row( byte_t* dst )
336     {
337         this->_io_dev.read( &_buffer.front(), _pitch );
338         _mirror_bits( _buffer );
339 
340         read_bit_row< gray1_image_t::view_t >( dst );
341     }
342 
343     // Read 4 bits image. The colors are encoded by an index.
read_4_bits_row(byte_t * dst)344     void read_4_bits_row( byte_t* dst )
345     {
346         this->_io_dev.read( &_buffer.front(), _pitch );
347         _swap_half_bytes( _buffer );
348 
349         read_bit_row< gray4_image_t::view_t >( dst );
350     }
351 
352     /// Read 8 bits image. The colors are encoded by an index.
read_8_bits_row(byte_t * dst)353     void read_8_bits_row( byte_t* dst )
354     {
355         this->_io_dev.read( &_buffer.front(), _pitch );
356 
357         read_bit_row< gray8_image_t::view_t >( dst );
358     }
359 
360     /// Read 15 or 16 bits image.
read_15_bits_row(byte_t * dst)361     void read_15_bits_row( byte_t* dst )
362     {
363         using dst_view_t = rgb8_view_t;
364 
365         dst_view_t dst_view = interleaved_view( this->_info._width
366                                               , 1
367                                               , (typename dst_view_t::value_type*) dst
368                                               , this->_pitch
369                                               );
370 
371         typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 );
372 
373         //
374         byte_t* src = &_buffer.front();
375         this->_io_dev.read( src, _pitch );
376 
377         for( dst_view_t::x_coord_t i = 0
378            ; i < this->_info._width
379            ; ++i, src += 2
380            )
381         {
382             int p = ( src[1] << 8 ) | src[0];
383 
384             int r = ((p & this->_mask.red.mask)   >> this->_mask.red.shift)   << (8 - this->_mask.red.width);
385             int g = ((p & this->_mask.green.mask) >> this->_mask.green.shift) << (8 - this->_mask.green.width);
386             int b = ((p & this->_mask.blue.mask)  >> this->_mask.blue.shift)  << (8 - this->_mask.blue.width);
387 
388             get_color( dst_it[i], red_t()   ) = static_cast< byte_t >( r );
389             get_color( dst_it[i], green_t() ) = static_cast< byte_t >( g );
390             get_color( dst_it[i], blue_t()  ) = static_cast< byte_t >( b );
391         }
392     }
393 
read_row(byte_t * dst)394     void read_row( byte_t* dst )
395     {
396         this->_io_dev.read( dst, _pitch );
397     }
398 
399 private:
400 
401     // the row pitch must be multiple of 4 bytes
402     int _pitch;
403 
404     std::vector<byte_t> _buffer;
405     detail::mirror_bits <std::vector<byte_t>, std::true_type> _mirror_bits;
406     detail::swap_half_bytes<std::vector<byte_t>, std::true_type> _swap_half_bytes;
407 
408     std::function<void(this_t*, byte_t*)> _read_function;
409 };
410 
411 } // namespace gil
412 } // namespace boost
413 
414 #endif
415