Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:56

0001 //
0002 // Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 #ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
0010 
0011 #include <boost/gil/extension/io/jpeg/tags.hpp>
0012 #include <boost/gil/extension/io/jpeg/detail/base.hpp>
0013 #include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp>
0014 
0015 #include <boost/gil/io/detail/dynamic.hpp>
0016 #include <boost/gil/io/base.hpp>
0017 #include <boost/gil/io/conversion_policies.hpp>
0018 #include <boost/gil/io/device.hpp>
0019 #include <boost/gil/io/reader_base.hpp>
0020 #include <boost/gil/io/typedefs.hpp>
0021 
0022 #include <csetjmp>
0023 #include <type_traits>
0024 #include <vector>
0025 
0026 namespace boost { namespace gil {
0027 
0028 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0029 #pragma warning(push)
0030 #pragma warning(disable:4512) //assignment operator could not be generated
0031 #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
0032 #endif
0033 
0034 ///
0035 /// JPEG Reader
0036 ///
0037 template< typename Device
0038         , typename ConversionPolicy
0039         >
0040 class reader< Device
0041             , jpeg_tag
0042             , ConversionPolicy
0043             >
0044     : public reader_base< jpeg_tag
0045                         , ConversionPolicy
0046                         >
0047     , public reader_backend< Device
0048                            , jpeg_tag
0049                            >
0050 {
0051 private:
0052 
0053     using this_t = reader<Device, jpeg_tag, ConversionPolicy>;
0054     using cc_t = typename ConversionPolicy::color_converter_type;
0055 
0056 public:
0057 
0058     using backend_t = reader_backend<Device, jpeg_tag>;
0059 
0060 public:
0061 
0062     //
0063     // Constructor
0064     //
0065     reader( const Device&                          io_dev
0066           , const image_read_settings< jpeg_tag >& settings
0067           )
0068     : reader_base< jpeg_tag
0069                  , ConversionPolicy
0070                  >()
0071 
0072     , backend_t( io_dev
0073                , settings
0074                )
0075     {}
0076 
0077     //
0078     // Constructor
0079     //
0080     reader( const Device&                                          io_dev
0081           , const typename ConversionPolicy::color_converter_type& cc
0082           , const image_read_settings< jpeg_tag >&                 settings
0083           )
0084     : reader_base< jpeg_tag
0085                  , ConversionPolicy
0086                  >( cc )
0087     , backend_t( io_dev
0088                , settings
0089                )
0090     {}
0091 
0092     template<typename View>
0093     void apply( const View& view )
0094     {
0095         // Fire exception in case of error.
0096         if( setjmp( this->_mark ))
0097         {
0098             this->raise_error();
0099         }
0100 
0101         this->get()->dct_method = this->_settings._dct_method;
0102 
0103         using is_read_and_convert_t = typename std::is_same
0104             <
0105                 ConversionPolicy,
0106                 detail::read_and_no_convert
0107             >::type;
0108 
0109         io_error_if( !detail::is_allowed< View >( this->_info
0110                                                 , is_read_and_convert_t()
0111                                                 )
0112                    , "Image types aren't compatible."
0113                    );
0114 
0115         if( jpeg_start_decompress( this->get() ) == false )
0116         {
0117             io_error( "Cannot start decompression." );
0118         }
0119 
0120         switch( this->_info._color_space )
0121         {
0122             case JCS_GRAYSCALE:
0123             {
0124                 this->_scanline_length = this->_info._width;
0125                 read_rows< gray8_pixel_t >( view );
0126 
0127                 break;
0128             }
0129 
0130             case JCS_RGB:
0131             //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB
0132             case JCS_YCbCr:
0133             {
0134                 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
0135 
0136                 read_rows< rgb8_pixel_t  >( view );
0137                 break;
0138             }
0139 
0140             case JCS_CMYK:
0141             //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK
0142             case JCS_YCCK:
0143             {
0144                 this->get()->out_color_space = JCS_CMYK;
0145                 this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value;
0146 
0147                 read_rows< cmyk8_pixel_t >( view );
0148 
0149                 break;
0150             }
0151             default: { io_error( "Unsupported jpeg color space." ); }
0152         }
0153 
0154         jpeg_finish_decompress ( this->get() );
0155     }
0156 
0157 private:
0158 
0159     template< typename ImagePixel
0160             , typename View
0161             >
0162     void read_rows( const View& view )
0163     {
0164         using buffer_t = std::vector<ImagePixel>;
0165         buffer_t buffer( this->_info._width );
0166 
0167         // In case of an error we'll jump back to here and fire an exception.
0168         // @todo Is the buffer above cleaned up when the exception is thrown?
0169         //       The strategy right now is to allocate necessary memory before
0170         //       the setjmp.
0171         if( setjmp( this->_mark ))
0172         {
0173             this->raise_error();
0174         }
0175 
0176 
0177         JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] );
0178 
0179         //Skip scanlines if necessary.
0180         for( int y = 0; y <  this->_settings._top_left.y; ++y )
0181         {
0182             io_error_if( jpeg_read_scanlines( this->get()
0183                                             , &row_adr
0184                                             , 1
0185                                             ) !=1
0186                        , "jpeg_read_scanlines: fail to read JPEG file"
0187                        );
0188         }
0189 
0190         // Read data.
0191         for( int y = 0; y < view.height(); ++y )
0192         {
0193             io_error_if( jpeg_read_scanlines( this->get()
0194                                             , &row_adr
0195                                             , 1
0196                                             ) != 1
0197                        , "jpeg_read_scanlines: fail to read JPEG file"
0198                        );
0199 
0200             typename buffer_t::iterator beg = buffer.begin() + this->_settings._top_left.x;
0201             typename buffer_t::iterator end = beg + this->_settings._dim.x;
0202 
0203             this->_cc_policy.read( beg
0204                                  , end
0205                                  , view.row_begin( y )
0206                                  );
0207         }
0208 
0209         //@todo: There might be a better way to do that.
0210         while( this->get()->output_scanline < this->get()->image_height )
0211         {
0212             io_error_if( jpeg_read_scanlines( this->get()
0213                                             , &row_adr
0214                                             , 1
0215                                             ) !=1
0216                        , "jpeg_read_scanlines: fail to read JPEG file"
0217                        );
0218         }
0219 
0220     }
0221 };
0222 
0223 namespace detail {
0224 
0225 struct jpeg_type_format_checker
0226 {
0227     jpeg_type_format_checker( jpeg_color_space::type color_space )
0228     : _color_space( color_space )
0229     {}
0230 
0231     template< typename Image >
0232     bool apply()
0233     {
0234         return is_read_supported< typename get_pixel_type< typename Image::view_t >::type
0235                                 , jpeg_tag
0236                                 >::_color_space == _color_space;
0237     }
0238 
0239 private:
0240 
0241     jpeg_color_space::type _color_space;
0242 };
0243 
0244 struct jpeg_read_is_supported
0245 {
0246     template< typename View >
0247     struct apply : public is_read_supported< typename get_pixel_type< View >::type
0248                                            , jpeg_tag
0249                                            >
0250     {};
0251 };
0252 
0253 } // namespace detail
0254 
0255 ///
0256 /// JPEG Dynamic Reader
0257 ///
0258 template< typename Device >
0259 class dynamic_image_reader< Device
0260                           , jpeg_tag
0261                           >
0262     : public reader< Device
0263                    , jpeg_tag
0264                    , detail::read_and_no_convert
0265                    >
0266 {
0267     using parent_t = reader<Device, jpeg_tag, detail::read_and_no_convert>;
0268 
0269 public:
0270 
0271     dynamic_image_reader( const Device&                          io_dev
0272                         , const image_read_settings< jpeg_tag >& settings
0273                         )
0274     : parent_t( io_dev
0275               , settings
0276               )
0277     {}
0278 
0279     template< typename ...Images >
0280     void apply( any_image< Images... >& images )
0281     {
0282         detail::jpeg_type_format_checker format_checker( this->_info._color_space != JCS_YCbCr
0283                                                        ? this->_info._color_space
0284                                                        : JCS_RGB
0285                                                        );
0286 
0287         if( !detail::construct_matched( images
0288                               , format_checker
0289                               ))
0290         {
0291             io_error( "No matching image type between those of the given any_image and that of the file" );
0292         }
0293         else
0294         {
0295             this->init_image( images
0296                             , this->_settings
0297                             );
0298 
0299             detail::dynamic_io_fnobj< detail::jpeg_read_is_supported
0300                                     , parent_t
0301                                     > op( this );
0302 
0303             variant2::visit( op
0304                            , view( images )
0305                            );
0306         }
0307     }
0308 };
0309 
0310 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0311 #pragma warning(pop)
0312 #endif
0313 
0314 } // gil
0315 } // boost
0316 
0317 #endif