Chris@16: /* Chris@16: Copyright 2005-2007 Adobe Systems Incorporated Chris@16: Chris@16: Use, modification and distribution are subject to the Boost Software License, Chris@16: Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: http://www.boost.org/LICENSE_1_0.txt). Chris@16: Chris@16: See http://opensource.adobe.com/gil for most recent version including documentation. Chris@16: */ Chris@16: Chris@16: /*************************************************************************************************/ Chris@16: Chris@16: #ifndef GIL_JPEG_IO_PRIVATE_H Chris@16: #define GIL_JPEG_IO_PRIVATE_H Chris@16: Chris@16: /// \file Chris@16: /// \brief Internal support for reading and writing JPEG files Chris@16: /// \author Hailin Jin and Lubomir Bourdev \n Chris@16: /// Adobe Systems Incorporated Chris@16: /// \date 2005-2007 \n Last updated September 24, 2006 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include "../../gil_all.hpp" Chris@16: #include "io_error.hpp" Chris@16: #include Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: // lbourdev: What is the advantage of having channel and colorspace together? Are there cases where they are interrelated? Chris@16: Chris@16: template Chris@16: struct jpeg_read_support_private { Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=false); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN); Chris@16: }; Chris@16: template <> Chris@16: struct jpeg_read_support_private { Chris@16: BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=true); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE); Chris@16: }; Chris@16: template <> Chris@16: struct jpeg_read_support_private { Chris@16: BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=true); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB); Chris@16: }; Chris@16: template <> Chris@16: struct jpeg_read_support_private { Chris@16: BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=true); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK); Chris@16: }; Chris@16: template Chris@16: struct jpeg_write_support_private { Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=false); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN); Chris@16: }; Chris@16: template <> Chris@16: struct jpeg_write_support_private { Chris@16: BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=true); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE); Chris@16: }; Chris@16: template <> Chris@16: struct jpeg_write_support_private { Chris@16: BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=true); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB); Chris@16: }; Chris@16: template <> Chris@16: struct jpeg_write_support_private { Chris@16: BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); Chris@16: BOOST_STATIC_CONSTANT(bool,is_supported=true); Chris@16: BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK); Chris@16: }; Chris@16: Chris@16: Chris@16: class jpeg_reader : public file_mgr { Chris@16: protected: Chris@16: jpeg_decompress_struct _cinfo; Chris@16: jpeg_error_mgr _jerr; Chris@16: Chris@16: void init() { Chris@16: _cinfo.err=jpeg_std_error(&_jerr); Chris@16: jpeg_create_decompress(&_cinfo); Chris@16: jpeg_stdio_src(&_cinfo,_fp.get()); Chris@16: jpeg_read_header(&_cinfo,TRUE); Chris@16: } Chris@16: public: Chris@16: jpeg_reader(FILE* file) : file_mgr(file) { init(); } Chris@16: jpeg_reader(const char* filename) : file_mgr(filename, "rb") { init(); } Chris@16: Chris@16: ~jpeg_reader() { jpeg_destroy_decompress(&_cinfo); } Chris@16: Chris@16: template Chris@16: void apply(const View& view) { Chris@16: 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... Chris@16: io_error_if(_cinfo.data_precision!=8,"jpeg_reader::apply(): this image file is not supported"); Chris@16: io_error_if(_cinfo.out_color_space!=jpeg_read_support_private::type, Chris@16: typename color_space_type::type>::color_type, Chris@16: "jpeg_reader::apply(): input view type does not match the image file"); Chris@16: io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader::apply(): input view dimensions do not match the image file"); Chris@16: std::vector::type> > > row(view.width()); Chris@16: JSAMPLE* row_address=(JSAMPLE*)&row.front(); Chris@16: for(int y=0;y Chris@16: void read_image(Image& im) { Chris@16: im.recreate(get_dimensions()); Chris@16: apply(view(im)); Chris@16: } Chris@16: Chris@16: point2 get_dimensions() const { Chris@16: return point2(_cinfo.image_width,_cinfo.image_height); Chris@16: } Chris@16: }; Chris@16: Chris@16: // This code will be simplified... Chris@16: template Chris@16: class jpeg_reader_color_convert : public jpeg_reader { Chris@16: private: Chris@16: CC _cc; Chris@16: public: Chris@16: jpeg_reader_color_convert(FILE* file,CC cc_in) : jpeg_reader(file),_cc(cc_in) {} Chris@16: jpeg_reader_color_convert(FILE* file) : jpeg_reader(file) {} Chris@16: jpeg_reader_color_convert(const char* filename,CC cc_in) : jpeg_reader(filename),_cc(cc_in) {} Chris@16: jpeg_reader_color_convert(const char* filename) : jpeg_reader(filename) {} Chris@16: template Chris@16: void apply(const View& view) { Chris@16: 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... Chris@16: io_error_if(_cinfo.data_precision!=8,"jpeg_reader_color_covert::apply(): this image file is not supported"); Chris@16: io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader_color_covert::apply(): input view dimensions don't match the image file"); Chris@16: switch (_cinfo.out_color_space) { Chris@16: case JCS_GRAYSCALE: { Chris@16: std::vector row(view.width()); Chris@16: JSAMPLE* row_address=(JSAMPLE*)&row.front(); Chris@16: for(int y=0;y(_cc)); Chris@16: } Chris@16: break; Chris@16: } Chris@16: case JCS_RGB: { Chris@16: std::vector row(view.width()); Chris@16: JSAMPLE* row_address=(JSAMPLE*)&row.front(); Chris@16: for(int y=0;y(_cc)); Chris@16: } Chris@16: break; Chris@16: } Chris@16: case JCS_CMYK: { Chris@16: std::vector row(view.width()); Chris@16: JSAMPLE* row_address=(JSAMPLE*)&row.front(); Chris@16: for(int y=0;y(_cc)); Chris@16: } Chris@16: break; Chris@16: } Chris@16: default: Chris@16: io_error("jpeg_reader_color_covert::apply(): unknown color type"); Chris@16: } Chris@16: jpeg_finish_decompress(&_cinfo); Chris@16: } Chris@16: template Chris@16: void read_image(Image& im) { Chris@16: im.recreate(get_dimensions()); Chris@16: apply(view(im)); Chris@16: } Chris@16: }; Chris@16: Chris@16: class jpeg_writer : public file_mgr { Chris@16: jpeg_compress_struct _cinfo; Chris@16: jpeg_error_mgr _jerr; Chris@16: Chris@16: void init() { Chris@16: _cinfo.err=jpeg_std_error(&_jerr); Chris@16: jpeg_create_compress(&_cinfo); Chris@16: jpeg_stdio_dest(&_cinfo,_fp.get()); Chris@16: } Chris@16: public: Chris@16: jpeg_writer(FILE* file) : file_mgr(file) { init(); } Chris@16: jpeg_writer(const char* filename) : file_mgr(filename, "wb") { init(); } Chris@16: ~jpeg_writer() { jpeg_destroy_compress(&_cinfo); } Chris@16: Chris@16: template Chris@16: void apply(const View& view,int quality=100) { Chris@16: _cinfo.image_width = (JDIMENSION)view.width(); Chris@16: _cinfo.image_height = (JDIMENSION)view.height(); Chris@16: _cinfo.input_components=num_channels::value; Chris@16: _cinfo.in_color_space = jpeg_write_support_private::type, Chris@16: typename color_space_type::type>::color_type; Chris@16: jpeg_set_defaults(&_cinfo); Chris@16: jpeg_set_quality(&_cinfo, quality, TRUE); Chris@16: jpeg_start_compress(&_cinfo, TRUE); Chris@16: std::vector::type> > > row(view.width()); Chris@16: JSAMPLE* row_address=(JSAMPLE*)&row.front(); Chris@16: for (int y=0;y