00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef GIL_JPEG_IO_PRIVATE_H
00014 #define GIL_JPEG_IO_PRIVATE_H
00015
00021
00022 #include <stdio.h>
00023 #include <boost/static_assert.hpp>
00024 #include <vector>
00025 #include "../../gil_all.hpp"
00026 #include "io_error.hpp"
00027
00028 namespace boost { namespace gil {
00029
00030 namespace detail {
00031
00032
00033
00034 template <typename Channel,typename ColorSpace>
00035 struct jpeg_read_support_private {
00036 BOOST_STATIC_CONSTANT(bool,is_supported=false);
00037 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN);
00038 };
00039 template <>
00040 struct jpeg_read_support_private<bits8,gray_t> {
00041 BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
00042 BOOST_STATIC_CONSTANT(bool,is_supported=true);
00043 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE);
00044 };
00045 template <>
00046 struct jpeg_read_support_private<bits8,rgb_t> {
00047 BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
00048 BOOST_STATIC_CONSTANT(bool,is_supported=true);
00049 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB);
00050 };
00051 template <>
00052 struct jpeg_read_support_private<bits8,cmyk_t> {
00053 BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
00054 BOOST_STATIC_CONSTANT(bool,is_supported=true);
00055 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK);
00056 };
00057 template <typename Channel,typename ColorSpace>
00058 struct jpeg_write_support_private {
00059 BOOST_STATIC_CONSTANT(bool,is_supported=false);
00060 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN);
00061 };
00062 template <>
00063 struct jpeg_write_support_private<bits8,gray_t> {
00064 BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
00065 BOOST_STATIC_CONSTANT(bool,is_supported=true);
00066 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE);
00067 };
00068 template <>
00069 struct jpeg_write_support_private<bits8,rgb_t> {
00070 BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
00071 BOOST_STATIC_CONSTANT(bool,is_supported=true);
00072 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB);
00073 };
00074 template <>
00075 struct jpeg_write_support_private<bits8,cmyk_t> {
00076 BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
00077 BOOST_STATIC_CONSTANT(bool,is_supported=true);
00078 BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK);
00079 };
00080
00081
00082 class jpeg_reader : public file_mgr {
00083 protected:
00084 jpeg_decompress_struct _cinfo;
00085 jpeg_error_mgr _jerr;
00086
00087 void init() {
00088 _cinfo.err=jpeg_std_error(&_jerr);
00089 jpeg_create_decompress(&_cinfo);
00090 jpeg_stdio_src(&_cinfo,_fp.get());
00091 jpeg_read_header(&_cinfo,TRUE);
00092 }
00093 public:
00094 jpeg_reader(FILE* file) : file_mgr(file) { init(); }
00095 jpeg_reader(const char* filename) : file_mgr(filename, "rb") { init(); }
00096
00097 ~jpeg_reader() { jpeg_destroy_decompress(&_cinfo); }
00098
00099 template <typename View>
00100 void apply(const View& view) {
00101 jpeg_start_decompress(&_cinfo);
00102 io_error_if(_cinfo.data_precision!=8,"jpeg_reader::apply(): this image file is not supported");
00103 io_error_if(_cinfo.out_color_space!=jpeg_read_support_private<typename channel_type<View>::type,
00104 typename color_space_type<View>::type>::color_type,
00105 "jpeg_reader::apply(): input view type does not match the image file");
00106 io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader::apply(): input view dimensions do not match the image file");
00107 std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width());
00108 JSAMPLE* row_address=(JSAMPLE*)&row.front();
00109 for(int y=0;y<view.height();++y) {
00110 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
00111 "jpeg_reader::apply(): fail to read JPEG file");
00112 std::copy(row.begin(),row.end(),view.row_begin(y));
00113 }
00114 jpeg_finish_decompress(&_cinfo);
00115 }
00116
00117 template <typename Image>
00118 void read_image(Image& im) {
00119 im.recreate(get_dimensions());
00120 apply(view(im));
00121 }
00122
00123 point2<std::ptrdiff_t> get_dimensions() const {
00124 return point2<std::ptrdiff_t>(_cinfo.image_width,_cinfo.image_height);
00125 }
00126 };
00127
00128
00129 template <typename CC>
00130 class jpeg_reader_color_convert : public jpeg_reader {
00131 private:
00132 CC _cc;
00133 public:
00134 jpeg_reader_color_convert(FILE* file,CC cc_in) : jpeg_reader(file),_cc(cc_in) {}
00135 jpeg_reader_color_convert(FILE* file) : jpeg_reader(file) {}
00136 jpeg_reader_color_convert(const char* filename,CC cc_in) : jpeg_reader(filename),_cc(cc_in) {}
00137 jpeg_reader_color_convert(const char* filename) : jpeg_reader(filename) {}
00138 template <typename View>
00139 void apply(const View& view) {
00140 jpeg_start_decompress(&_cinfo);
00141 io_error_if(_cinfo.data_precision!=8,"jpeg_reader_color_covert::apply(): this image file is not supported");
00142 io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader_color_covert::apply(): input view dimensions don't match the image file");
00143 switch (_cinfo.out_color_space) {
00144 case JCS_GRAYSCALE: {
00145 std::vector<gray8_pixel_t> row(view.width());
00146 JSAMPLE* row_address=(JSAMPLE*)&row.front();
00147 for(int y=0;y<view.height();++y) {
00148 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
00149 "jpeg_reader_color_covert::apply(): fail to read JPEG file");
00150 std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray8_ref_t, typename View::value_type,CC>(_cc));
00151 }
00152 break;
00153 }
00154 case JCS_RGB: {
00155 std::vector<rgb8_pixel_t> row(view.width());
00156 JSAMPLE* row_address=(JSAMPLE*)&row.front();
00157 for(int y=0;y<view.height();++y) {
00158 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
00159 "jpeg_reader_color_covert::apply(): fail to read JPEG file");
00160 std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb8_ref_t, typename View::value_type,CC>(_cc));
00161 }
00162 break;
00163 }
00164 case JCS_CMYK: {
00165 std::vector<cmyk8_pixel_t> row(view.width());
00166 JSAMPLE* row_address=(JSAMPLE*)&row.front();
00167 for(int y=0;y<view.height();++y) {
00168 io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
00169 "jpeg_reader_color_covert::apply(): fail to read JPEG file");
00170 std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<cmyk8_ref_t, typename View::value_type,CC>(_cc));
00171 }
00172 break;
00173 }
00174 default:
00175 io_error("jpeg_reader_color_covert::apply(): unknown color type");
00176 }
00177 jpeg_finish_decompress(&_cinfo);
00178 }
00179 template <typename Image>
00180 void read_image(Image& im) {
00181 im.recreate(get_dimensions());
00182 apply(view(im));
00183 }
00184 };
00185
00186 class jpeg_writer : public file_mgr {
00187 jpeg_compress_struct _cinfo;
00188 jpeg_error_mgr _jerr;
00189
00190 void init() {
00191 _cinfo.err=jpeg_std_error(&_jerr);
00192 jpeg_create_compress(&_cinfo);
00193 jpeg_stdio_dest(&_cinfo,_fp.get());
00194 }
00195 public:
00196 jpeg_writer(FILE* file) : file_mgr(file) { init(); }
00197 jpeg_writer(const char* filename) : file_mgr(filename, "wb") { init(); }
00198 ~jpeg_writer() { jpeg_destroy_compress(&_cinfo); }
00199
00200 template <typename View>
00201 void apply(const View& view,int quality=100) {
00202 _cinfo.image_width = (JDIMENSION)view.width();
00203 _cinfo.image_height = (JDIMENSION)view.height();
00204 _cinfo.input_components=num_channels<View>::value;
00205 _cinfo.in_color_space = jpeg_write_support_private<typename channel_type<View>::type,
00206 typename color_space_type<View>::type>::color_type;
00207 jpeg_set_defaults(&_cinfo);
00208 jpeg_set_quality(&_cinfo, quality, TRUE);
00209 jpeg_start_compress(&_cinfo, TRUE);
00210 std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width());
00211 JSAMPLE* row_address=(JSAMPLE*)&row.front();
00212 for (int y=0;y<view.height(); ++y) {
00213 std::copy(view.row_begin(y),view.row_end(y),row.begin());
00214 io_error_if(jpeg_write_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1) != 1,
00215 "jpeg_writer::apply(): fail to write file");
00216 }
00217 jpeg_finish_compress(&_cinfo);
00218 }
00219 };
00220
00221 }
00222
00223 } }
00224
00225 #endif