reader_backend.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //
  2. // Copyright 2012 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_READER_BACKEND_HPP
  9. #define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READER_BACKEND_HPP
  10. #include <boost/gil/extension/io/bmp/tags.hpp>
  11. namespace boost { namespace gil {
  12. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  13. #pragma warning(push)
  14. #pragma warning(disable:4512) //assignment operator could not be generated
  15. #endif
  16. /// Color channel mask
  17. struct bit_field
  18. {
  19. unsigned int mask; // Bit mask at corresponding position
  20. unsigned int width; // Bit width of the mask
  21. unsigned int shift; // Bit position from right to left
  22. };
  23. /// BMP color masks
  24. struct color_mask
  25. {
  26. bit_field red; // Red bits
  27. bit_field green; // Green bits
  28. bit_field blue; // Blue bits
  29. };
  30. ///
  31. /// BMP Backend
  32. ///
  33. template< typename Device >
  34. struct reader_backend< Device
  35. , bmp_tag
  36. >
  37. {
  38. public:
  39. using format_tag_t = bmp_tag;
  40. public:
  41. reader_backend( const Device& io_dev
  42. , const image_read_settings< bmp_tag >& settings
  43. )
  44. : _io_dev ( io_dev )
  45. , _settings( settings )
  46. , _info()
  47. , _scanline_length( 0 )
  48. , _palette()
  49. {
  50. read_header();
  51. if( _settings._dim.x == 0 )
  52. {
  53. _settings._dim.x = _info._width;
  54. }
  55. if( _settings._dim.y == 0 )
  56. {
  57. _settings._dim.y = _info._height;
  58. }
  59. }
  60. void read_header()
  61. {
  62. // the magic number used to identify the BMP file:
  63. // 0x42 0x4D (ASCII code points for B and M)
  64. if( _io_dev.read_uint16() == 0x424D )
  65. {
  66. io_error( "Wrong magic number for bmp file." );
  67. }
  68. // the size of the BMP file in bytes
  69. _io_dev.read_uint32();
  70. // reserved; actual value depends on the application that creates the image
  71. _io_dev.read_uint16();
  72. // reserved; actual value depends on the application that creates the image
  73. _io_dev.read_uint16();
  74. _info._offset = _io_dev.read_uint32();
  75. // bitmap information
  76. // the size of this header ( 40 bytes )
  77. _info._header_size = _io_dev.read_uint32();
  78. if( _info._header_size == bmp_header_size::_win32_info_size )
  79. {
  80. _info._width = _io_dev.read_uint32();
  81. _info._height = _io_dev.read_uint32();
  82. if (_info._height < 0)
  83. {
  84. _info._height = -_info._height;
  85. _info._top_down = true;
  86. }
  87. // the number of color planes being used. Must be set to 1.
  88. _io_dev.read_uint16();
  89. _info._bits_per_pixel = _io_dev.read_uint16();
  90. _info._compression = _io_dev.read_uint32();
  91. _info._image_size = _io_dev.read_uint32();
  92. _info._horizontal_resolution = _io_dev.read_uint32();
  93. _info._vertical_resolution = _io_dev.read_uint32();
  94. _info._num_colors = _io_dev.read_uint32();
  95. _info._num_important_colors = _io_dev.read_uint32();
  96. }
  97. else if( _info._header_size == bmp_header_size::_os2_info_size )
  98. {
  99. _info._width = static_cast< bmp_image_width::type >( _io_dev.read_uint16() );
  100. _info._height = static_cast< bmp_image_height::type >( _io_dev.read_uint16() );
  101. // the number of color planes being used. Must be set to 1.
  102. _io_dev.read_uint16();
  103. _info._bits_per_pixel = _io_dev.read_uint16();
  104. _info._compression = bmp_compression::_rgb;
  105. // not used
  106. _info._image_size = 0;
  107. _info._horizontal_resolution = 0;
  108. _info._vertical_resolution = 0;
  109. _info._num_colors = 0;
  110. _info._num_important_colors = 0;
  111. }
  112. else if (_info._header_size > bmp_header_size::_win32_info_size)
  113. {
  114. // could be v4 or v5
  115. // see MSDN: Bitmap Header Types ( BITMAPV4HEADER or BITMAPV5HEADER )
  116. _info._width = _io_dev.read_uint32();
  117. _info._height = _io_dev.read_uint32();
  118. // the number of color planes being used. Must be set to 1.
  119. _io_dev.read_uint16();
  120. _info._bits_per_pixel = _io_dev.read_uint16();
  121. _info._compression = _io_dev.read_uint32();
  122. _info._image_size = _io_dev.read_uint32();
  123. _info._horizontal_resolution = _io_dev.read_uint32();
  124. _info._vertical_resolution = _io_dev.read_uint32();
  125. _info._num_colors = _io_dev.read_uint32();
  126. _info._num_important_colors = _io_dev.read_uint32();
  127. }
  128. else
  129. {
  130. io_error( "Invalid BMP info header." );
  131. }
  132. _info._valid = true;
  133. }
  134. void read_palette()
  135. {
  136. int entries = this->_info._num_colors;
  137. if( entries == 0 )
  138. {
  139. entries = 1u << this->_info._bits_per_pixel;
  140. }
  141. _palette.resize( entries, rgba8_pixel_t(0, 0, 0, 0));
  142. for( int i = 0; i < entries; ++i )
  143. {
  144. get_color( _palette[i], blue_t() ) = _io_dev.read_uint8();
  145. get_color( _palette[i], green_t() ) = _io_dev.read_uint8();
  146. get_color( _palette[i], red_t() ) = _io_dev.read_uint8();
  147. // there are 4 entries when windows header
  148. // but 3 for os2 header
  149. if( _info._header_size == bmp_header_size::_win32_info_size )
  150. {
  151. _io_dev.read_uint8();
  152. }
  153. } // for
  154. }
  155. /// Check if image is large enough.
  156. void check_image_size( const point_t& img_dim )
  157. {
  158. if( _settings._dim.x > 0 )
  159. {
  160. if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
  161. }
  162. else
  163. {
  164. if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
  165. }
  166. if( _settings._dim.y > 0 )
  167. {
  168. if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
  169. }
  170. else
  171. {
  172. if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
  173. }
  174. }
  175. public:
  176. Device _io_dev;
  177. image_read_settings< bmp_tag > _settings;
  178. image_read_info< bmp_tag > _info;
  179. std::size_t _scanline_length;
  180. ///@todo make it an image.
  181. std::vector< rgba8_pixel_t > _palette;
  182. color_mask _mask;
  183. };
  184. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  185. #pragma warning(pop)
  186. #endif
  187. } // namespace gil
  188. } // namespace boost
  189. #endif