Modules | Alphabetical List | Class List | Directories | File List | File Members | GIL Home Page # png_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 #ifndef GIL_PNG_IO_PRIVATE_H
    00013 #define GIL_PNG_IO_PRIVATE_H
    00014
    00020
    00021 #include <algorithm>
    00022 #include <vector>
    00023 #include <boost/static_assert.hpp>
    00024 #include "../../gil_all.hpp"
    00025 #include "io_error.hpp"
    00026
    00027 namespace boost { namespace gil {
    00028
    00029 namespace detail {
    00030
    00031 static const size_t PNG_BYTES_TO_CHECK = 4;
    00032
    00033 // lbourdev: These can be greatly simplified, for example:
    00034 template <typename Cs> struct png_color_type {BOOST_STATIC_CONSTANT(int,color_type=0);};
    00035 template<> struct png_color_type<gray_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); };
    00036 template<> struct png_color_type<rgb_t>  { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); };
    00037 template<> struct png_color_type<rgba_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); };
    00038
    00039 template <typename Channel,typename ColorSpace> struct png_is_supported {BOOST_STATIC_CONSTANT(bool,value=false);};
    00040 template <> struct png_is_supported<bits8,gray_t>  {BOOST_STATIC_CONSTANT(bool,value=true);};
    00041 template <> struct png_is_supported<bits8,rgb_t>   {BOOST_STATIC_CONSTANT(bool,value=true);};
    00042 template <> struct png_is_supported<bits8,rgba_t>  {BOOST_STATIC_CONSTANT(bool,value=true);};
    00043 template <> struct png_is_supported<bits16,gray_t> {BOOST_STATIC_CONSTANT(bool,value=true);};
    00044 template <> struct png_is_supported<bits16,rgb_t>  {BOOST_STATIC_CONSTANT(bool,value=true);};
    00045 template <> struct png_is_supported<bits16,rgba_t> {BOOST_STATIC_CONSTANT(bool,value=true);};
    00046
    00047 template <typename Channel> struct png_bit_depth {BOOST_STATIC_CONSTANT(int,bit_depth=sizeof(Channel)*8);};
    00048
    00049 template <typename Channel,typename ColorSpace>
    00050 struct png_read_support_private {
    00051     BOOST_STATIC_CONSTANT(bool,is_supported=false);
    00052     BOOST_STATIC_CONSTANT(int,bit_depth=0);
    00053     BOOST_STATIC_CONSTANT(int,color_type=0);
    00054 };
    00055 template <>
    00056 struct png_read_support_private<bits8,gray_t> {
    00057     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00058     BOOST_STATIC_CONSTANT(int,bit_depth=8);
    00059     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
    00060 };
    00061 template <>
    00062 struct png_read_support_private<bits8,rgb_t> {
    00063     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00064     BOOST_STATIC_CONSTANT(int,bit_depth=8);
    00065     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
    00066 };
    00067 template <>
    00068 struct png_read_support_private<bits8,rgba_t> {
    00069     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00070     BOOST_STATIC_CONSTANT(int,bit_depth=8);
    00071     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
    00072 };
    00073 template <>
    00074 struct png_read_support_private<bits16,gray_t> {
    00075     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00076     BOOST_STATIC_CONSTANT(int,bit_depth=16);
    00077     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
    00078 };
    00079 template <>
    00080 struct png_read_support_private<bits16,rgb_t> {
    00081     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00082     BOOST_STATIC_CONSTANT(int,bit_depth=16);
    00083     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
    00084 };
    00085 template <>
    00086 struct png_read_support_private<bits16,rgba_t> {
    00087     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00088     BOOST_STATIC_CONSTANT(int,bit_depth=16);
    00089     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
    00090 };
    00091
    00092 template <typename Channel,typename ColorSpace>
    00093 struct png_write_support_private {
    00094     BOOST_STATIC_CONSTANT(bool,is_supported=false);
    00095     BOOST_STATIC_CONSTANT(int,bit_depth=0);
    00096     BOOST_STATIC_CONSTANT(int,color_type=0);
    00097 };
    00098 template <>
    00099 struct png_write_support_private<bits8,gray_t> {
    00100     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00101     BOOST_STATIC_CONSTANT(int,bit_depth=8);
    00102     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
    00103 };
    00104 template <>
    00105 struct png_write_support_private<bits8,rgb_t> {
    00106     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00107     BOOST_STATIC_CONSTANT(int,bit_depth=8);
    00108     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
    00109 };
    00110 template <>
    00111 struct png_write_support_private<bits8,rgba_t> {
    00112     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00113     BOOST_STATIC_CONSTANT(int,bit_depth=8);
    00114     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
    00115 };
    00116 template <>
    00117 struct png_write_support_private<bits16,gray_t> {
    00118     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00119     BOOST_STATIC_CONSTANT(int,bit_depth=16);
    00120     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
    00121 };
    00122 template <>
    00123 struct png_write_support_private<bits16,rgb_t> {
    00124     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00125     BOOST_STATIC_CONSTANT(int,bit_depth=16);
    00126     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
    00127 };
    00128 template <>
    00129 struct png_write_support_private<bits16,rgba_t> {
    00130     BOOST_STATIC_CONSTANT(bool,is_supported=true);
    00131     BOOST_STATIC_CONSTANT(int,bit_depth=16);
    00132     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
    00133 };
    00134
    00135 class png_reader : public file_mgr {
    00136 protected:
    00137     png_structp _png_ptr;
    00138     png_infop _info_ptr;
    00139
    00140     void init() {
    00141         char buf[PNG_BYTES_TO_CHECK];
    00142         // read in some of the signature bytes
    00143         io_error_if(fread(buf, 1, PNG_BYTES_TO_CHECK, get()) != detail::PNG_BYTES_TO_CHECK,
    00144                     "png_check_validity: fail to read file");
    00145         // compare the first PNG_BYTES_TO_CHECK bytes of the signature.
    00146         io_error_if(png_sig_cmp((png_bytep)buf, (png_size_t)0, detail::PNG_BYTES_TO_CHECK)!=0,
    00147                     "png_check_validity: invalid png file");
    00148
    00149         _png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
    00150         io_error_if(_png_ptr==NULL,"png_get_file_size: fail to call png_create_write_struct()");
    00151         // allocate/initialize the image information data
    00152         _info_ptr = png_create_info_struct(_png_ptr);
    00153         if (_info_ptr == NULL) {
    00154             png_destroy_read_struct(&_png_ptr,png_infopp_NULL,png_infopp_NULL);
    00155             io_error("png_get_file_size: fail to call png_create_info_struct()");
    00156         }
    00157         if (setjmp(png_jmpbuf(_png_ptr))) {
    00158             //free all of the memory associated with the png_ptr and info_ptr
    00159             png_destroy_read_struct(&_png_ptr, &_info_ptr, png_infopp_NULL);
    00160             io_error("png_get_file_size: fail to call setjmp()");
    00161         }
    00162         png_init_io(_png_ptr, get());
    00163         png_set_sig_bytes(_png_ptr,PNG_BYTES_TO_CHECK);
    00164         png_read_info(_png_ptr, _info_ptr);
    00165         if (little_endian() && png_get_bit_depth(_png_ptr,_info_ptr)>8)
    00166             png_set_swap(_png_ptr);
    00167     }
    00168 public:
    00169     png_reader(FILE* file          ) : file_mgr(file)           { init(); }
    00170     png_reader(const char* filename) : file_mgr(filename, "rb") { init(); }
    00171
    00172     ~png_reader() {
    00173         png_destroy_read_struct(&_png_ptr,&_info_ptr,png_infopp_NULL);
    00174     }
    00175     point2<std::ptrdiff_t> get_dimensions() {
    00176         return point2<std::ptrdiff_t>(png_get_image_width(_png_ptr,_info_ptr),
    00177                                       png_get_image_height(_png_ptr,_info_ptr));
    00178     }
    00179     template <typename View>
    00180     void apply(const View& view) {
    00181         png_uint_32 width, height;
    00182         int bit_depth, color_type, interlace_type;
    00183         png_get_IHDR(_png_ptr, _info_ptr,
    00184                      &width, &height,&bit_depth,&color_type,&interlace_type,
    00185                      int_p_NULL, int_p_NULL);
    00186         io_error_if(((png_uint_32)view.width()!=width || (png_uint_32)view.height()!= height),
    00187                     "png_read_view: input view size does not match PNG file size");
    00188
    00189         if(png_read_support_private<typename channel_type<View>::type,
    00190                                     typename color_space_type<View>::type>::bit_depth!=bit_depth ||
    00191            png_read_support_private<typename channel_type<View>::type,
    00192                                     typename color_space_type<View>::type>::color_type!=color_type)
    00193             io_error("png_read_view: input view type is incompatible with the image type");
    00194
    00195         std::vector<pixel<typename channel_type<View>::type,
    00196                           layout<typename color_space_type<View>::type> > > row(width);
    00197         for(png_uint_32 y=0;y<height;++y) {
    00198             png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00199             std::copy(row.begin(),row.end(),view.row_begin(y));
    00200         }
    00201         png_read_end(_png_ptr,NULL);
    00202     }
    00203
    00204     template <typename Image>
    00205     void read_image(Image& im) {
    00206         im.recreate(get_dimensions());
    00207         apply(view(im));
    00208     }
    00209 };
    00210
    00211 // This code will be simplified...
    00212 template <typename CC>
    00213 class png_reader_color_convert : public png_reader {
    00214 private:
    00215     CC _cc;
    00216 public:
    00217     png_reader_color_convert(FILE* file          ,CC cc_in) : png_reader(file),_cc(cc_in) {}
    00218     png_reader_color_convert(FILE* file          ) : png_reader(file) {}
    00219     png_reader_color_convert(const char* filename,CC cc_in) : png_reader(filename),_cc(cc_in) {}
    00220     png_reader_color_convert(const char* filename) : png_reader(filename) {}
    00221     template <typename View>
    00222     void apply(const View& view) {
    00223         png_uint_32 width, height;
    00224         int bit_depth, color_type, interlace_type;
    00225         png_get_IHDR(_png_ptr, _info_ptr,
    00226                      &width, &height,&bit_depth,&color_type,&interlace_type,
    00227                      int_p_NULL, int_p_NULL);
    00228         io_error_if(((png_uint_32)view.width()!=width || (png_uint_32)view.height()!= height),
    00229                     "png_reader_color_convert::apply(): input view size does not match PNG file size");
    00230         switch (color_type) {
    00231         case PNG_COLOR_TYPE_GRAY:
    00232             switch (bit_depth) {
    00233             case 8: {
    00234                 std::vector<gray8_pixel_t> row(width);
    00235                 for(png_uint_32 y=0;y<height;++y) {
    00236                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00237                     std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray8_ref_t,typename View::value_type,CC>(_cc));
    00238                 }
    00239                 break;
    00240             }
    00241             case 16: {
    00242                 std::vector<gray16_pixel_t> row(width);
    00243                 for(png_uint_32 y=0;y<height;++y) {
    00244                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00245                     std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray16_ref_t,typename View::value_type,CC>(_cc));
    00246                 }
    00247                 break;
    00248             }
    00249             default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth");
    00250             }
    00251             break;
    00252         case PNG_COLOR_TYPE_RGB:
    00253             switch (bit_depth) {
    00254             case 8: {
    00255                 std::vector<rgb8_pixel_t> row(width);
    00256                 for(png_uint_32 y=0;y<height;++y) {
    00257                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00258                     std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb8_ref_t,typename View::value_type,CC>(_cc));
    00259                 }
    00260                 break;
    00261             }
    00262             case 16: {
    00263                 std::vector<rgb16_pixel_t> row(width);
    00264                 for(png_uint_32 y=0;y<height;++y) {
    00265                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00266                     std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb16_ref_t,typename View::value_type,CC>(_cc));
    00267                 }
    00268                 break;
    00269             }
    00270             default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth");
    00271             }
    00272             break;
    00273         case PNG_COLOR_TYPE_RGBA:
    00274             switch (bit_depth) {
    00275             case 8: {
    00276                 std::vector<rgba8_pixel_t> row(width);
    00277                 for(png_uint_32 y=0;y<height;++y) {
    00278                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00279                     std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgba8_ref_t,typename View::value_type,CC>(_cc));
    00280                 }
    00281                 break;
    00282             }
    00283             case 16: {
    00284                 std::vector<rgba16_pixel_t> row(width);
    00285                 for(png_uint_32 y=0;y<height;++y) {
    00286                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
    00287                     std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgba16_ref_t,typename View::value_type,CC>(_cc));
    00288                 }
    00289                 break;
    00290             }
    00291             default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth");
    00292             }
    00293             break;
    00294         default: io_error("png_reader_color_convert::apply(): unknown color type");
    00295         }
    00296         png_read_end(_png_ptr,NULL);
    00297     }
    00298     template <typename Image>
    00299     void read_image(Image& im) {
    00300         im.recreate(get_dimensions());
    00301         apply(view(im));
    00302     }
    00303 };
    00304
    00305
    00306 class png_writer : public file_mgr {
    00307 protected:
    00308     png_structp _png_ptr;
    00309     png_infop _info_ptr;
    00310
    00311     void init() {
    00312         _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
    00313         io_error_if(!_png_ptr,"png_write_initialize: fail to call png_create_write_struct()");
    00314         _info_ptr = png_create_info_struct(_png_ptr);
    00315         if (!_info_ptr) {
    00316             png_destroy_write_struct(&_png_ptr,png_infopp_NULL);
    00317             io_error("png_write_initialize: fail to call png_create_info_struct()");
    00318         }
    00319         if (setjmp(png_jmpbuf(_png_ptr))) {
    00320             png_destroy_write_struct(&_png_ptr, &_info_ptr);
    00321             io_error("png_write_initialize: fail to call setjmp(png_jmpbuf())");
    00322         }
    00323         png_init_io(_png_ptr,get());
    00324     }
    00325 public:
    00326     png_writer(FILE* file          ) : file_mgr(file)           { init(); }
    00327     png_writer(const char* filename) : file_mgr(filename, "wb") { init(); }
    00328
    00329     ~png_writer() {
    00330         png_destroy_write_struct(&_png_ptr,&_info_ptr);
    00331     }
    00332     template <typename View>
    00333     void apply(const View& view) {
    00334         png_set_IHDR(_png_ptr, _info_ptr, view.width(), view.height(),
    00335                      png_write_support_private<typename channel_type<View>::type,
    00336                                                typename color_space_type<View>::type>::bit_depth,
    00337                      png_write_support_private<typename channel_type<View>::type,
    00338                                                typename color_space_type<View>::type>::color_type,
    00339                      PNG_INTERLACE_NONE,
    00340                      PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
    00341         png_write_info(_png_ptr,_info_ptr);
    00342         if (little_endian() &&
    00343             png_write_support_private<typename channel_type<View>::type,
    00344                                       typename color_space_type<View>::type>::bit_depth>8)
    00345             png_set_swap(_png_ptr);
    00346         std::vector<pixel<typename channel_type<View>::type,
    00347                           layout<typename color_space_type<View>::type> > > row(view.width());
    00348         for(int y=0;y<view.height();++y) {
    00349             std::copy(view.row_begin(y),view.row_end(y),row.begin());
    00350             png_write_row(_png_ptr,(png_bytep)&row.front());
    00351         }
    00352         png_write_end(_png_ptr,_info_ptr);
    00353     }
    00354 };
    00355
    00356 } // namespace detail
    00357 } }  // namespace boost::gil
    00358
    00359 #endif