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_TARGA_DETAIL_READER_BACKEND_HPP
9 #define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READER_BACKEND_HPP
10 
11 #include <boost/gil/extension/io/targa/tags.hpp>
12 
13 namespace boost { namespace gil {
14 
15 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
16 #pragma warning(push)
17 #pragma warning(disable:4512) //assignment operator could not be generated
18 #endif
19 
20 ///
21 /// Targa Backend
22 ///
23 template< typename Device >
24 struct reader_backend< Device
25                      , targa_tag
26                      >
27 {
28 public:
29 
30     typedef targa_tag format_tag_t;
31 
32 public:
33 
reader_backendboost::gil::reader_backend34     reader_backend( const Device&                           io_dev
35                   , const image_read_settings< targa_tag >& settings
36                   )
37     : _io_dev  ( io_dev   )
38     , _scanline_length(0)
39     , _settings( settings )
40     , _info()
41     {
42         read_header();
43 
44         if( _settings._dim.x == 0 )
45         {
46             _settings._dim.x = _info._width;
47         }
48 
49         if( _settings._dim.y == 0 )
50         {
51             _settings._dim.y = _info._height;
52         }
53     }
54 
read_headerboost::gil::reader_backend55     void read_header()
56     {
57         _info._header_size = targa_header_size::_size;
58 
59         _info._offset = _io_dev.read_uint8() + _info._header_size;
60 
61         _info._color_map_type = _io_dev.read_uint8();
62         _info._image_type = _io_dev.read_uint8();
63 
64         _info._color_map_start  = _io_dev.read_uint16();
65         _info._color_map_length = _io_dev.read_uint16();
66         _info._color_map_depth  = _io_dev.read_uint8();
67 
68         _info._x_origin = _io_dev.read_uint16();
69         _info._y_origin = _io_dev.read_uint16();
70 
71         _info._width  = _io_dev.read_uint16();
72         _info._height = _io_dev.read_uint16();
73 
74         if( _info._width < 1 || _info._height < 1 )
75         {
76             io_error( "Invalid dimension for targa file" );
77         }
78 
79         _info._bits_per_pixel = _io_dev.read_uint8();
80         if( _info._bits_per_pixel != 24 && _info._bits_per_pixel != 32 )
81         {
82             io_error( "Unsupported bit depth for targa file" );
83         }
84 
85         _info._descriptor = _io_dev.read_uint8();
86 
87         // According to TGA specs, http://www.gamers.org/dEngine/quake3/TGA.txt,
88         // the image descriptor byte is:
89         //
90         // For Data Type 1, This entire byte should be set to 0.
91         if (_info._image_type == 1 && _info._descriptor != 0)
92         {
93             io_error("Unsupported descriptor for targa file");
94         }
95         else if (_info._bits_per_pixel == 24)
96         {
97             // Bits 3-0 - For the Targa 24, it should be 0.
98             if ((_info._descriptor & 0x0FU) != 0)
99             {
100                 io_error("Unsupported descriptor for targa file");
101             }
102         }
103         else if (_info._bits_per_pixel == 32)
104         {
105             // Bits 3-0 - For Targa 32, it should be 8.
106             if (_info._descriptor != 8 && _info._descriptor != 40)
107             {
108                 io_error("Unsupported descriptor for targa file");
109             }
110         }
111         else
112         {
113             io_error("Unsupported descriptor for targa file");
114         }
115 
116         if (_info._descriptor & 32)
117         {
118             _info._screen_origin_bit = true;
119         }
120 
121         _info._valid = true;
122     }
123 
124     /// Check if image is large enough.
check_image_sizeboost::gil::reader_backend125     void check_image_size( const point_t& img_dim )
126     {
127         if( _settings._dim.x > 0 )
128         {
129             if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
130         }
131         else
132         {
133             if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
134         }
135 
136 
137         if( _settings._dim.y > 0 )
138         {
139             if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
140         }
141         else
142         {
143             if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
144         }
145     }
146 
147 public:
148 
149     Device _io_dev;
150 
151     std::size_t _scanline_length;
152 
153     image_read_settings< targa_tag > _settings;
154     image_read_info< targa_tag >     _info;
155 };
156 
157 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
158 #pragma warning(pop)
159 #endif
160 
161 } // namespace gil
162 } // namespace boost
163 
164 #endif
165