diff options
Diffstat (limited to 'boost/gil/extension/io/jpeg/detail/read.hpp')
-rw-r--r-- | boost/gil/extension/io/jpeg/detail/read.hpp | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/boost/gil/extension/io/jpeg/detail/read.hpp b/boost/gil/extension/io/jpeg/detail/read.hpp new file mode 100644 index 0000000000..f3f5a8afef --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/read.hpp @@ -0,0 +1,331 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev + 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_JPEG_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <csetjmp> +#include <vector> +#include <boost/gil/extension/io/jpeg/tags.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/jpeg/detail/base.hpp> +#include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +/// +/// JPEG Reader +/// +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , jpeg_tag + , ConversionPolicy + > + : public reader_base< jpeg_tag + , ConversionPolicy + > + , public reader_backend< Device + , jpeg_tag + > +{ +private: + + typedef reader< Device + , jpeg_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, jpeg_tag > backend_t; + +public: + + // + // Constructor + // + reader( const Device& io_dev + , const image_read_settings< jpeg_tag >& settings + ) + : reader_base< jpeg_tag + , ConversionPolicy + >() + + , backend_t( io_dev + , settings + ) + {} + + // + // Constructor + // + reader( const Device& io_dev + , const typename ConversionPolicy::color_converter_type& cc + , const image_read_settings< jpeg_tag >& settings + ) + : reader_base< jpeg_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + {} + + template<typename View> + void apply( const View& view ) + { + // Fire exception in case of error. + if( setjmp( this->_mark )) + { + this->raise_error(); + } + + this->get()->dct_method = this->_settings._dct_method; + + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info + , is_read_and_convert_t() + ) + , "Image types aren't compatible." + ); + + if( jpeg_start_decompress( this->get() ) == false ) + { + io_error( "Cannot start decompression." ); + } + + switch( this->_info._color_space ) + { + case JCS_GRAYSCALE: + { + this->_scanline_length = this->_info._width; + read_rows< gray8_pixel_t >( view ); + + break; + } + + case JCS_RGB: + //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB + case JCS_YCbCr: + { + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + read_rows< rgb8_pixel_t >( view ); + break; + } + + case JCS_CMYK: + //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK + case JCS_YCCK: + { + this->get()->out_color_space = JCS_CMYK; + this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value; + + read_rows< cmyk8_pixel_t >( view ); + + break; + } + default: { io_error( "Unsupported jpeg color space." ); } + } + + jpeg_finish_decompress ( this->get() ); + } + +private: + + template< typename ImagePixel + , typename View + > + void read_rows( const View& view ) + { + typedef std::vector<ImagePixel> buffer_t; + buffer_t buffer( this->_info._width ); + + // In case of an error we'll jump back to here and fire an exception. + // @todo Is the buffer above cleaned up when the exception is thrown? + // The strategy right now is to allocate necessary memory before + // the setjmp. + if( setjmp( this->_mark )) + { + this->raise_error(); + } + + + JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] ); + + //Skip scanlines if necessary. + for( int y = 0; y < this->_settings._top_left.y; ++y ) + { + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) !=1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + } + + // Read data. + for( int y = 0; y < view.height(); ++y ) + { + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) != 1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + + typename buffer_t::iterator beg = buffer.begin() + this->_settings._top_left.x; + typename buffer_t::iterator end = beg + this->_settings._dim.x; + + this->_cc_policy.read( beg + , end + , view.row_begin( y ) + ); + } + + //@todo: There might be a better way to do that. + while( this->get()->output_scanline < this->get()->image_height ) + { + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) !=1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + } + + } +}; + +namespace detail { + +struct jpeg_type_format_checker +{ + jpeg_type_format_checker( jpeg_color_space::type color_space ) + : _color_space( color_space ) + {} + + template< typename Image > + bool apply() + { + return is_read_supported< typename get_pixel_type< typename Image::view_t >::type + , jpeg_tag + >::_color_space == _color_space; + } + +private: + + jpeg_color_space::type _color_space; +}; + +struct jpeg_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , jpeg_tag + > + {}; +}; + +} // namespace detail + +/// +/// JPEG Dynamic Reader +/// +template< typename Device > +class dynamic_image_reader< Device + , jpeg_tag + > + : public reader< Device + , jpeg_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , jpeg_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< jpeg_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::jpeg_type_format_checker format_checker( this->_info._color_space != JCS_YCbCr + ? this->_info._color_space + : JCS_RGB + ); + + if( !construct_matched( images + , format_checker + )) + { + io_error( "No matching image type between those of the given any_image and that of the file" ); + } + else + { + this->init_image( images + , this->_settings + ); + + detail::dynamic_io_fnobj< detail::jpeg_read_is_supported + , parent_t + > op( this ); + + apply_operation( view( images ) + , op + ); + } + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif |