]>
Commit | Line | Data |
---|---|---|
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 |