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