]> git.sesse.net Git - casparcg/blob - dependencies/boost/boost/gil/extension/io/jpeg_io_private.hpp
Manually merged pull request #222
[casparcg] / dependencies / boost / boost / gil / extension / io / jpeg_io_private.hpp
1 /*
2     Copyright 2005-2007 Adobe Systems Incorporated
3    
4     Use, modification and distribution are subject to the Boost Software License,
5     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6     http://www.boost.org/LICENSE_1_0.txt).
7
8     See http://opensource.adobe.com/gil for most recent version including documentation.
9 */
10
11 /*************************************************************************************************/
12
13 #ifndef GIL_JPEG_IO_PRIVATE_H
14 #define GIL_JPEG_IO_PRIVATE_H
15
16 /// \file
17 /// \brief  Internal support for reading and writing JPEG files
18 /// \author Hailin Jin and Lubomir Bourdev \n
19 ///         Adobe Systems Incorporated
20 /// \date   2005-2007 \n Last updated September 24, 2006
21
22 #include <stdio.h>
23 #include <boost/static_assert.hpp>
24 #include <vector>
25 #include "../../gil_all.hpp"
26 #include "io_error.hpp"
27 #include <jpeglib.h>
28
29 namespace boost { namespace gil {
30
31 namespace detail {
32
33 // lbourdev: What is the advantage of having channel and colorspace together? Are there cases where they are interrelated?
34
35 template <typename Channel,typename ColorSpace>
36 struct jpeg_read_support_private {
37     BOOST_STATIC_CONSTANT(bool,is_supported=false);
38     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN);
39 };
40 template <>
41 struct jpeg_read_support_private<bits8,gray_t> {
42     BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
43     BOOST_STATIC_CONSTANT(bool,is_supported=true);
44     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE);
45 };
46 template <>
47 struct jpeg_read_support_private<bits8,rgb_t> {
48     BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
49     BOOST_STATIC_CONSTANT(bool,is_supported=true);
50     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB);
51 };
52 template <>
53 struct jpeg_read_support_private<bits8,cmyk_t> {
54     BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
55     BOOST_STATIC_CONSTANT(bool,is_supported=true);
56     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK);
57 };
58 template <typename Channel,typename ColorSpace>
59 struct jpeg_write_support_private {
60     BOOST_STATIC_CONSTANT(bool,is_supported=false);
61     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN);
62 };
63 template <>
64 struct jpeg_write_support_private<bits8,gray_t> {
65     BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
66     BOOST_STATIC_CONSTANT(bool,is_supported=true);
67     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE);
68 };
69 template <>
70 struct jpeg_write_support_private<bits8,rgb_t> {
71     BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
72     BOOST_STATIC_CONSTANT(bool,is_supported=true);
73     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB);
74 };
75 template <>
76 struct jpeg_write_support_private<bits8,cmyk_t> {
77     BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
78     BOOST_STATIC_CONSTANT(bool,is_supported=true);
79     BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK);
80 };
81
82
83 class jpeg_reader : public file_mgr {
84 protected:
85     jpeg_decompress_struct  _cinfo;
86     jpeg_error_mgr          _jerr;
87
88     void init() {
89         _cinfo.err=jpeg_std_error(&_jerr);
90         jpeg_create_decompress(&_cinfo);
91         jpeg_stdio_src(&_cinfo,_fp.get());
92         jpeg_read_header(&_cinfo,TRUE);
93     }
94 public:
95     jpeg_reader(FILE* file)           : file_mgr(file)           { init(); }
96     jpeg_reader(const char* filename) : file_mgr(filename, "rb") { init(); }
97
98     ~jpeg_reader() { jpeg_destroy_decompress(&_cinfo); }
99
100     template <typename View>
101     void apply(const View& view) {
102         jpeg_start_decompress(&_cinfo);    // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state...
103         io_error_if(_cinfo.data_precision!=8,"jpeg_reader::apply(): this image file is not supported");
104         io_error_if(_cinfo.out_color_space!=jpeg_read_support_private<typename channel_type<View>::type,
105                                                                       typename color_space_type<View>::type>::color_type,
106                     "jpeg_reader::apply(): input view type does not match the image file");
107         io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader::apply(): input view dimensions do not match the image file");
108         std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width());
109         JSAMPLE* row_address=(JSAMPLE*)&row.front();
110         for(int y=0;y<view.height();++y) {
111             io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
112                         "jpeg_reader::apply(): fail to read JPEG file");
113             std::copy(row.begin(),row.end(),view.row_begin(y));
114         }
115         jpeg_finish_decompress(&_cinfo);
116     }
117     
118     template <typename Image>
119     void read_image(Image& im) {
120         im.recreate(get_dimensions());
121         apply(view(im));
122     }
123
124     point2<std::ptrdiff_t> get_dimensions() const {
125         return point2<std::ptrdiff_t>(_cinfo.image_width,_cinfo.image_height);
126     }
127 };
128
129 // This code will be simplified...
130 template <typename CC>
131 class jpeg_reader_color_convert : public jpeg_reader {
132 private:
133     CC _cc;
134 public:
135     jpeg_reader_color_convert(FILE* file,CC cc_in)           : jpeg_reader(file),_cc(cc_in) {}
136     jpeg_reader_color_convert(FILE* file)           : jpeg_reader(file) {}
137     jpeg_reader_color_convert(const char* filename,CC cc_in) : jpeg_reader(filename),_cc(cc_in) {}
138     jpeg_reader_color_convert(const char* filename) : jpeg_reader(filename) {}
139     template <typename View>
140     void apply(const View& view) {
141         jpeg_start_decompress(&_cinfo);    // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state...
142         io_error_if(_cinfo.data_precision!=8,"jpeg_reader_color_covert::apply(): this image file is not supported");
143         io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader_color_covert::apply(): input view dimensions don't match the image file");
144         switch (_cinfo.out_color_space) {
145         case JCS_GRAYSCALE: {
146             std::vector<gray8_pixel_t> row(view.width());
147             JSAMPLE* row_address=(JSAMPLE*)&row.front();
148             for(int y=0;y<view.height();++y) {
149                 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
150                             "jpeg_reader_color_covert::apply(): fail to read JPEG file");
151                 std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray8_ref_t, typename View::value_type,CC>(_cc));
152             }
153             break;
154         }
155         case JCS_RGB: {
156             std::vector<rgb8_pixel_t> row(view.width());
157             JSAMPLE* row_address=(JSAMPLE*)&row.front();
158             for(int y=0;y<view.height();++y) {
159                 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
160                             "jpeg_reader_color_covert::apply(): fail to read JPEG file");
161                 std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb8_ref_t, typename View::value_type,CC>(_cc));
162             }
163             break;
164         }
165         case JCS_CMYK: {
166             std::vector<cmyk8_pixel_t> row(view.width());
167             JSAMPLE* row_address=(JSAMPLE*)&row.front();
168             for(int y=0;y<view.height();++y) {
169                 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
170                             "jpeg_reader_color_covert::apply(): fail to read JPEG file");
171                 std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<cmyk8_ref_t, typename View::value_type,CC>(_cc));
172             }
173             break;
174         }
175         default:
176             io_error("jpeg_reader_color_covert::apply(): unknown color type");
177         }
178         jpeg_finish_decompress(&_cinfo);
179     }    
180     template <typename Image>
181     void read_image(Image& im) {
182         im.recreate(get_dimensions());
183         apply(view(im));
184     }
185 };
186
187 class jpeg_writer : public file_mgr {
188     jpeg_compress_struct _cinfo;
189     jpeg_error_mgr _jerr;
190
191     void init() {
192         _cinfo.err=jpeg_std_error(&_jerr);
193         jpeg_create_compress(&_cinfo);
194         jpeg_stdio_dest(&_cinfo,_fp.get());
195     }
196 public:
197     jpeg_writer(FILE* file)           : file_mgr(file)           { init(); }
198     jpeg_writer(const char* filename) : file_mgr(filename, "wb") { init(); }
199     ~jpeg_writer() { jpeg_destroy_compress(&_cinfo); }
200     
201     template <typename View>
202     void apply(const View& view,int quality=100) {
203         _cinfo.image_width  = (JDIMENSION)view.width();
204         _cinfo.image_height = (JDIMENSION)view.height();
205         _cinfo.input_components=num_channels<View>::value;
206         _cinfo.in_color_space = jpeg_write_support_private<typename channel_type<View>::type,
207                                                            typename color_space_type<View>::type>::color_type;
208         jpeg_set_defaults(&_cinfo);
209         jpeg_set_quality(&_cinfo, quality, TRUE);
210         jpeg_start_compress(&_cinfo, TRUE);
211         std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width());
212         JSAMPLE* row_address=(JSAMPLE*)&row.front();
213         for (int y=0;y<view.height(); ++y) {
214             std::copy(view.row_begin(y),view.row_end(y),row.begin());
215             io_error_if(jpeg_write_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1) != 1,
216                         "jpeg_writer::apply(): fail to write file");
217         }
218         jpeg_finish_compress(&_cinfo);
219     }
220 };
221
222 } // namespace detail
223
224 } }  // namespace boost::gil
225
226 #endif