2 // Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
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
8 #ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
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>
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>
23 #include <type_traits>
26 namespace boost { namespace gil {
28 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
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
37 template< typename Device
38 , typename ConversionPolicy
44 : public reader_base< jpeg_tag
47 , public reader_backend< Device
53 using this_t = reader<Device, jpeg_tag, ConversionPolicy>;
54 using cc_t = typename ConversionPolicy::color_converter_type;
58 using backend_t = reader_backend<Device, jpeg_tag>;
65 reader( const Device& io_dev
66 , const image_read_settings< jpeg_tag >& settings
68 : reader_base< jpeg_tag
80 reader( const Device& io_dev
81 , const typename ConversionPolicy::color_converter_type& cc
82 , const image_read_settings< jpeg_tag >& settings
84 : reader_base< jpeg_tag
92 template<typename View>
93 void apply( const View& view )
95 // Fire exception in case of error.
96 if( setjmp( this->_mark ))
101 this->get()->dct_method = this->_settings._dct_method;
103 using is_read_and_convert_t = typename std::is_same
106 detail::read_and_no_convert
109 io_error_if( !detail::is_allowed< View >( this->_info
110 , is_read_and_convert_t()
112 , "Image types aren't compatible."
115 if( jpeg_start_decompress( this->get() ) == false )
117 io_error( "Cannot start decompression." );
120 switch( this->_info._color_space )
124 this->_scanline_length = this->_info._width;
125 read_rows< gray8_pixel_t >( view );
131 //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB
134 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
136 read_rows< rgb8_pixel_t >( view );
141 //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK
144 this->get()->out_color_space = JCS_CMYK;
145 this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value;
147 read_rows< cmyk8_pixel_t >( view );
151 default: { io_error( "Unsupported jpeg color space." ); }
154 jpeg_finish_decompress ( this->get() );
159 template< typename ImagePixel
162 void read_rows( const View& view )
164 using buffer_t = std::vector<ImagePixel>;
165 buffer_t buffer( this->_info._width );
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
171 if( setjmp( this->_mark ))
177 JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] );
179 //Skip scanlines if necessary.
180 for( int y = 0; y < this->_settings._top_left.y; ++y )
182 io_error_if( jpeg_read_scanlines( this->get()
186 , "jpeg_read_scanlines: fail to read JPEG file"
191 for( int y = 0; y < view.height(); ++y )
193 io_error_if( jpeg_read_scanlines( this->get()
197 , "jpeg_read_scanlines: fail to read JPEG file"
200 typename buffer_t::iterator beg = buffer.begin() + this->_settings._top_left.x;
201 typename buffer_t::iterator end = beg + this->_settings._dim.x;
203 this->_cc_policy.read( beg
205 , view.row_begin( y )
209 //@todo: There might be a better way to do that.
210 while( this->get()->output_scanline < this->get()->image_height )
212 io_error_if( jpeg_read_scanlines( this->get()
216 , "jpeg_read_scanlines: fail to read JPEG file"
225 struct jpeg_type_format_checker
227 jpeg_type_format_checker( jpeg_color_space::type color_space )
228 : _color_space( color_space )
231 template< typename Image >
234 return is_read_supported< typename get_pixel_type< typename Image::view_t >::type
236 >::_color_space == _color_space;
241 jpeg_color_space::type _color_space;
244 struct jpeg_read_is_supported
246 template< typename View >
247 struct apply : public is_read_supported< typename get_pixel_type< View >::type
253 } // namespace detail
256 /// JPEG Dynamic Reader
258 template< typename Device >
259 class dynamic_image_reader< Device
262 : public reader< Device
264 , detail::read_and_no_convert
267 using parent_t = reader<Device, jpeg_tag, detail::read_and_no_convert>;
271 dynamic_image_reader( const Device& io_dev
272 , const image_read_settings< jpeg_tag >& settings
279 template< typename Images >
280 void apply( any_image< Images >& images )
282 detail::jpeg_type_format_checker format_checker( this->_info._color_space != JCS_YCbCr
283 ? this->_info._color_space
287 if( !construct_matched( images
291 io_error( "No matching image type between those of the given any_image and that of the file" );
295 this->init_image( images
299 detail::dynamic_io_fnobj< detail::jpeg_read_is_supported
303 apply_operation( view( images )
310 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)