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

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google