summaryrefslogtreecommitdiff
path: root/boost/gil/extension/io/bmp/detail/reader_backend.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/gil/extension/io/bmp/detail/reader_backend.hpp')
-rw-r--r--boost/gil/extension/io/bmp/detail/reader_backend.hpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/boost/gil/extension/io/bmp/detail/reader_backend.hpp b/boost/gil/extension/io/bmp/detail/reader_backend.hpp
new file mode 100644
index 0000000000..589a5e3c4f
--- /dev/null
+++ b/boost/gil/extension/io/bmp/detail/reader_backend.hpp
@@ -0,0 +1,258 @@
+/*
+ Copyright 2012 Christian Henning
+ Use, modification and distribution are subject to the Boost Software License,
+ Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt).
+*/
+
+/*************************************************************************************************/
+
+#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READER_BACKEND_HPP
+#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READER_BACKEND_HPP
+
+////////////////////////////////////////////////////////////////////////////////////////
+/// \file
+/// \brief
+/// \author Christian Henning \n
+///
+/// \date 2012 \n
+///
+////////////////////////////////////////////////////////////////////////////////////////
+
+#include <boost/gil/extension/io/bmp/tags.hpp>
+
+namespace boost { namespace gil {
+
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
+#pragma warning(push)
+#pragma warning(disable:4512) //assignment operator could not be generated
+#endif
+
+/// Color channel mask
+struct bit_field
+{
+ unsigned int mask; // Bit mask at corresponding position
+ unsigned int width; // Bit width of the mask
+ unsigned int shift; // Bit position from right to left
+};
+
+/// BMP color masks
+struct color_mask
+{
+ bit_field red; // Red bits
+ bit_field green; // Green bits
+ bit_field blue; // Blue bits
+};
+
+
+///
+/// BMP Backend
+///
+template< typename Device >
+struct reader_backend< Device
+ , bmp_tag
+ >
+{
+public:
+
+ typedef bmp_tag format_tag_t;
+
+public:
+
+ reader_backend( const Device& io_dev
+ , const image_read_settings< bmp_tag >& settings
+ )
+ : _io_dev ( io_dev )
+ , _settings( settings )
+ , _info()
+ , _scanline_length( 0 )
+ , _palette()
+ {
+ read_header();
+
+ if( _settings._dim.x == 0 )
+ {
+ _settings._dim.x = _info._width;
+ }
+
+ if( _settings._dim.y == 0 )
+ {
+ _settings._dim.y = _info._height;
+ }
+ }
+
+ void read_header()
+ {
+ // the magic number used to identify the BMP file:
+ // 0x42 0x4D (ASCII code points for B and M)
+ if( _io_dev.read_uint16() == 0x424D )
+ {
+ io_error( "Wrong magic number for bmp file." );
+ }
+
+ // the size of the BMP file in bytes
+ _io_dev.read_uint32();
+
+ // reserved; actual value depends on the application that creates the image
+ _io_dev.read_uint16();
+ // reserved; actual value depends on the application that creates the image
+ _io_dev.read_uint16();
+
+ _info._offset = _io_dev.read_uint32();
+
+
+ // bitmap information
+
+ // the size of this header ( 40 bytes )
+ _info._header_size = _io_dev.read_uint32();
+
+ if( _info._header_size == bmp_header_size::_win32_info_size )
+ {
+ _info._width = _io_dev.read_uint32();
+ _info._height = _io_dev.read_uint32();
+
+ if (_info._height < 0)
+ {
+ _info._height = -_info._height;
+ _info._top_down = true;
+ }
+
+ // the number of color planes being used. Must be set to 1.
+ _io_dev.read_uint16();
+
+ _info._bits_per_pixel = _io_dev.read_uint16();
+
+ _info._compression = _io_dev.read_uint32();
+
+ _info._image_size = _io_dev.read_uint32();
+
+ _info._horizontal_resolution = _io_dev.read_uint32();
+ _info._vertical_resolution = _io_dev.read_uint32();
+
+ _info._num_colors = _io_dev.read_uint32();
+ _info._num_important_colors = _io_dev.read_uint32();
+
+ }
+ else if( _info._header_size == bmp_header_size::_os2_info_size )
+ {
+ _info._width = static_cast< bmp_image_width::type >( _io_dev.read_uint16() );
+ _info._height = static_cast< bmp_image_height::type >( _io_dev.read_uint16() );
+
+ // the number of color planes being used. Must be set to 1.
+ _io_dev.read_uint16();
+
+ _info._bits_per_pixel = _io_dev.read_uint16();
+
+ _info._compression = bmp_compression::_rgb;
+
+ // not used
+ _info._image_size = 0;
+ _info._horizontal_resolution = 0;
+ _info._vertical_resolution = 0;
+ _info._num_colors = 0;
+ _info._num_important_colors = 0;
+ }
+ else if (_info._header_size > bmp_header_size::_win32_info_size)
+ {
+ // could be v4 or v5
+ // see MSDN: Bitmap Header Types ( BITMAPV4HEADER or BITMAPV5HEADER )
+
+ _info._width = _io_dev.read_uint32();
+ _info._height = _io_dev.read_uint32();
+
+ // the number of color planes being used. Must be set to 1.
+ _io_dev.read_uint16();
+
+ _info._bits_per_pixel = _io_dev.read_uint16();
+
+ _info._compression = _io_dev.read_uint32();
+
+ _info._image_size = _io_dev.read_uint32();
+
+ _info._horizontal_resolution = _io_dev.read_uint32();
+ _info._vertical_resolution = _io_dev.read_uint32();
+
+ _info._num_colors = _io_dev.read_uint32();
+ _info._num_important_colors = _io_dev.read_uint32();
+ }
+ else
+ {
+ io_error( "Invalid BMP info header." );
+ }
+
+ _info._valid = true;
+ }
+
+ void read_palette()
+ {
+ int entries = this->_info._num_colors;
+
+ if( entries == 0 )
+ {
+ entries = 1u << this->_info._bits_per_pixel;
+ }
+
+ _palette.resize( entries, rgba8_pixel_t(0, 0, 0, 0));
+
+ for( int i = 0; i < entries; ++i )
+ {
+ get_color( _palette[i], blue_t() ) = _io_dev.read_uint8();
+ get_color( _palette[i], green_t() ) = _io_dev.read_uint8();
+ get_color( _palette[i], red_t() ) = _io_dev.read_uint8();
+
+ // there are 4 entries when windows header
+ // but 3 for os2 header
+ if( _info._header_size == bmp_header_size::_win32_info_size )
+ {
+ _io_dev.read_uint8();
+ }
+
+ } // for
+ }
+
+ /// Check if image is large enough.
+ void check_image_size( const point_t& img_dim )
+ {
+ if( _settings._dim.x > 0 )
+ {
+ if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
+ }
+ else
+ {
+ if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
+ }
+
+
+ if( _settings._dim.y > 0 )
+ {
+ if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
+ }
+ else
+ {
+ if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
+ }
+ }
+
+public:
+
+ Device _io_dev;
+
+ image_read_settings< bmp_tag > _settings;
+ image_read_info< bmp_tag > _info;
+
+ std::size_t _scanline_length;
+
+ ///@todo make it an image.
+ std::vector< rgba8_pixel_t > _palette;
+
+ color_mask _mask;
+};
+
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
+#pragma warning(pop)
+#endif
+
+} // namespace gil
+} // namespace boost
+
+#endif