Modules | Alphabetical List | Class List | Directories | File List | File Members | GIL Home Page # jpeg_io_private.hpp Go to the documentation of this file.
    00001 /*
    00002     Copyright 2005-2007 Adobe Systems Incorporated
    00003
    00004     Use, modification and distribution are subject to the Boost Software License,
    00005     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    00006     http://www.boost.org/LICENSE_1_0.txt).
    00007
    00008     See http://opensource.adobe.com/gil for most recent version including documentation.
    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 // lbourdev: What is the advantage of having channel and colorspace together? Are there cases where they are interrelated?
    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);    // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state...
    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 // This code will be simplified...
    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);    // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state...
    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 } // namespace detail
    00222
    00223 } }  // namespace boost::gil
    00224
    00225 #endif