]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/extension/io/jpeg/detail/read.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / gil / extension / io / jpeg / detail / read.hpp
1 //
2 // Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
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_JPEG_DETAIL_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
10
11 #include <boost/gil/extension/io/jpeg/tags.hpp>
12 #include <boost/gil/extension/io/jpeg/detail/base.hpp>
13 #include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp>
14
15 #include <boost/gil/io/base.hpp>
16 #include <boost/gil/io/conversion_policies.hpp>
17 #include <boost/gil/io/device.hpp>
18 #include <boost/gil/io/dynamic_io_new.hpp>
19 #include <boost/gil/io/reader_base.hpp>
20 #include <boost/gil/io/typedefs.hpp>
21
22 #include <csetjmp>
23 #include <type_traits>
24 #include <vector>
25
26 namespace boost { namespace gil {
27
28 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
29 #pragma warning(push)
30 #pragma warning(disable:4512) //assignment operator could not be generated
31 #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
32 #endif
33
34 ///
35 /// JPEG Reader
36 ///
37 template< typename Device
38 , typename ConversionPolicy
39 >
40 class reader< Device
41 , jpeg_tag
42 , ConversionPolicy
43 >
44 : public reader_base< jpeg_tag
45 , ConversionPolicy
46 >
47 , public reader_backend< Device
48 , jpeg_tag
49 >
50 {
51 private:
52
53 using this_t = reader<Device, jpeg_tag, ConversionPolicy>;
54 using cc_t = typename ConversionPolicy::color_converter_type;
55
56 public:
57
58 using backend_t = reader_backend<Device, jpeg_tag>;
59
60 public:
61
62 //
63 // Constructor
64 //
65 reader( const Device& io_dev
66 , const image_read_settings< jpeg_tag >& settings
67 )
68 : reader_base< jpeg_tag
69 , ConversionPolicy
70 >()
71
72 , backend_t( io_dev
73 , settings
74 )
75 {}
76
77 //
78 // Constructor
79 //
80 reader( const Device& io_dev
81 , const typename ConversionPolicy::color_converter_type& cc
82 , const image_read_settings< jpeg_tag >& settings
83 )
84 : reader_base< jpeg_tag
85 , ConversionPolicy
86 >( cc )
87 , backend_t( io_dev
88 , settings
89 )
90 {}
91
92 template<typename View>
93 void apply( const View& view )
94 {
95 // Fire exception in case of error.
96 if( setjmp( this->_mark ))
97 {
98 this->raise_error();
99 }
100
101 this->get()->dct_method = this->_settings._dct_method;
102
103 using is_read_and_convert_t = typename std::is_same
104 <
105 ConversionPolicy,
106 detail::read_and_no_convert
107 >::type;
108
109 io_error_if( !detail::is_allowed< View >( this->_info
110 , is_read_and_convert_t()
111 )
112 , "Image types aren't compatible."
113 );
114
115 if( jpeg_start_decompress( this->get() ) == false )
116 {
117 io_error( "Cannot start decompression." );
118 }
119
120 switch( this->_info._color_space )
121 {
122 case JCS_GRAYSCALE:
123 {
124 this->_scanline_length = this->_info._width;
125 read_rows< gray8_pixel_t >( view );
126
127 break;
128 }
129
130 case JCS_RGB:
131 //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB
132 case JCS_YCbCr:
133 {
134 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
135
136 read_rows< rgb8_pixel_t >( view );
137 break;
138 }
139
140 case JCS_CMYK:
141 //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK
142 case JCS_YCCK:
143 {
144 this->get()->out_color_space = JCS_CMYK;
145 this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value;
146
147 read_rows< cmyk8_pixel_t >( view );
148
149 break;
150 }
151 default: { io_error( "Unsupported jpeg color space." ); }
152 }
153
154 jpeg_finish_decompress ( this->get() );
155 }
156
157 private:
158
159 template< typename ImagePixel
160 , typename View
161 >
162 void read_rows( const View& view )
163 {
164 using buffer_t = std::vector<ImagePixel>;
165 buffer_t buffer( this->_info._width );
166
167 // In case of an error we'll jump back to here and fire an exception.
168 // @todo Is the buffer above cleaned up when the exception is thrown?
169 // The strategy right now is to allocate necessary memory before
170 // the setjmp.
171 if( setjmp( this->_mark ))
172 {
173 this->raise_error();
174 }
175
176
177 JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] );
178
179 //Skip scanlines if necessary.
180 for( int y = 0; y < this->_settings._top_left.y; ++y )
181 {
182 io_error_if( jpeg_read_scanlines( this->get()
183 , &row_adr
184 , 1
185 ) !=1
186 , "jpeg_read_scanlines: fail to read JPEG file"
187 );
188 }
189
190 // Read data.
191 for( int y = 0; y < view.height(); ++y )
192 {
193 io_error_if( jpeg_read_scanlines( this->get()
194 , &row_adr
195 , 1
196 ) != 1
197 , "jpeg_read_scanlines: fail to read JPEG file"
198 );
199
200 typename buffer_t::iterator beg = buffer.begin() + this->_settings._top_left.x;
201 typename buffer_t::iterator end = beg + this->_settings._dim.x;
202
203 this->_cc_policy.read( beg
204 , end
205 , view.row_begin( y )
206 );
207 }
208
209 //@todo: There might be a better way to do that.
210 while( this->get()->output_scanline < this->get()->image_height )
211 {
212 io_error_if( jpeg_read_scanlines( this->get()
213 , &row_adr
214 , 1
215 ) !=1
216 , "jpeg_read_scanlines: fail to read JPEG file"
217 );
218 }
219
220 }
221 };
222
223 namespace detail {
224
225 struct jpeg_type_format_checker
226 {
227 jpeg_type_format_checker( jpeg_color_space::type color_space )
228 : _color_space( color_space )
229 {}
230
231 template< typename Image >
232 bool apply()
233 {
234 return is_read_supported< typename get_pixel_type< typename Image::view_t >::type
235 , jpeg_tag
236 >::_color_space == _color_space;
237 }
238
239 private:
240
241 jpeg_color_space::type _color_space;
242 };
243
244 struct jpeg_read_is_supported
245 {
246 template< typename View >
247 struct apply : public is_read_supported< typename get_pixel_type< View >::type
248 , jpeg_tag
249 >
250 {};
251 };
252
253 } // namespace detail
254
255 ///
256 /// JPEG Dynamic Reader
257 ///
258 template< typename Device >
259 class dynamic_image_reader< Device
260 , jpeg_tag
261 >
262 : public reader< Device
263 , jpeg_tag
264 , detail::read_and_no_convert
265 >
266 {
267 using parent_t = reader<Device, jpeg_tag, detail::read_and_no_convert>;
268
269 public:
270
271 dynamic_image_reader( const Device& io_dev
272 , const image_read_settings< jpeg_tag >& settings
273 )
274 : parent_t( io_dev
275 , settings
276 )
277 {}
278
279 template< typename Images >
280 void apply( any_image< Images >& images )
281 {
282 detail::jpeg_type_format_checker format_checker( this->_info._color_space != JCS_YCbCr
283 ? this->_info._color_space
284 : JCS_RGB
285 );
286
287 if( !construct_matched( images
288 , format_checker
289 ))
290 {
291 io_error( "No matching image type between those of the given any_image and that of the file" );
292 }
293 else
294 {
295 this->init_image( images
296 , this->_settings
297 );
298
299 detail::dynamic_io_fnobj< detail::jpeg_read_is_supported
300 , parent_t
301 > op( this );
302
303 apply_operation( view( images )
304 , op
305 );
306 }
307 }
308 };
309
310 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
311 #pragma warning(pop)
312 #endif
313
314 } // gil
315 } // boost
316
317 #endif