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_SCANLINE_READ_HPP 9 #define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SCANLINE_READ_HPP 10 11 12 #include <boost/gil/extension/io/jpeg/detail/base.hpp> 13 #include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp> 14 #include <boost/gil/extension/io/jpeg/detail/reader_backend.hpp> 15 16 #include <boost/gil/io/base.hpp> 17 #include <boost/gil/io/conversion_policies.hpp> 18 #include <boost/gil/io/device.hpp> 19 #include <boost/gil/io/reader_base.hpp> 20 #include <boost/gil/io/scanline_read_iterator.hpp> 21 #include <boost/gil/io/typedefs.hpp> 22 23 #include <csetjmp> 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:4611) //interaction between '_setjmp' and C++ object destruction is non-portable 31 #endif 32 33 /// 34 /// JPEG Scanline Reader 35 /// 36 template< typename Device > 37 class scanline_reader< Device 38 , jpeg_tag 39 > 40 : public reader_backend< Device 41 , jpeg_tag 42 > 43 { 44 public: 45 46 using tag_t = jpeg_tag; 47 using backend_t = reader_backend<Device, tag_t>; 48 using this_t = scanline_reader<Device, tag_t>; 49 using iterator_t = scanline_read_iterator<this_t>; 50 51 public: scanline_reader(Device & device,const image_read_settings<jpeg_tag> & settings)52 scanline_reader( Device& device 53 , const image_read_settings< jpeg_tag >& settings 54 ) 55 : reader_backend< Device 56 , jpeg_tag 57 >( device 58 , settings 59 ) 60 { 61 initialize(); 62 } 63 read(byte_t * dst,int)64 void read( byte_t* dst 65 , int 66 ) 67 { 68 // Fire exception in case of error. 69 if( setjmp( this->_mark )) { this->raise_error(); } 70 71 // read data 72 read_scanline( dst ); 73 } 74 75 /// Skip over a scanline. skip(byte_t * dst,int)76 void skip( byte_t* dst, int ) 77 { 78 // Fire exception in case of error. 79 if( setjmp( this->_mark )) { this->raise_error(); } 80 81 // read data 82 read_scanline( dst ); 83 } 84 begin()85 iterator_t begin() { return iterator_t( *this ); } end()86 iterator_t end() { return iterator_t( *this, this->_info._height ); } 87 88 private: 89 initialize()90 void initialize() 91 { 92 this->get()->dct_method = this->_settings._dct_method; 93 94 io_error_if( jpeg_start_decompress( this->get() ) == false 95 , "Cannot start decompression." ); 96 97 switch( this->_info._color_space ) 98 { 99 case JCS_GRAYSCALE: 100 { 101 this->_scanline_length = this->_info._width; 102 103 break; 104 } 105 106 case JCS_RGB: 107 //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB 108 case JCS_YCbCr: 109 { 110 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; 111 112 break; 113 } 114 115 116 case JCS_CMYK: 117 //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK 118 case JCS_YCCK: 119 { 120 this->get()->out_color_space = JCS_CMYK; 121 this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value; 122 123 break; 124 } 125 126 default: { io_error( "Unsupported jpeg color space." ); } 127 } 128 } 129 read_scanline(byte_t * dst)130 void read_scanline( byte_t* dst ) 131 { 132 JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( dst ); 133 134 // Read data. 135 io_error_if( jpeg_read_scanlines( this->get() 136 , &row_adr 137 , 1 138 ) != 1 139 , "jpeg_read_scanlines: fail to read JPEG file" 140 ); 141 142 } 143 }; 144 145 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 146 #pragma warning(pop) 147 #endif 148 149 } // namespace gil 150 } // namespace boost 151 152 #endif 153