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