scanline_read.hpp 13 KB

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