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