Adobe Systems, Inc.

png_io_private.hpp

Go to the documentation of this file.
00001 /*
00002   Copyright 2005-2006 Adobe Systems Incorporated
00003   Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
00004   or a copy at http://opensource.adobe.com/licenses.html)
00005 */
00006 
00007 /*************************************************************************************************/
00008 
00009 #ifndef GIL_PNG_IO_PRIVATE_H
00010 #define GIL_PNG_IO_PRIVATE_H
00011 
00017 
00018 #include <algorithm>
00019 #include <vector>
00020 #include <png.h>
00021 #include <boost/static_assert.hpp>
00022 #include "../../core/gil_config.hpp"
00023 #include "../../core/gray.hpp"
00024 #include "../../core/rgb.hpp"
00025 #include "../../core/rgba.hpp"
00026 #include "../../core/image.hpp"
00027 #include "../../core/typedefs.hpp"
00028 #include "io_error.hpp"
00029 
00030 ADOBE_GIL_NAMESPACE_BEGIN
00031 
00032 namespace detail {
00033 
00034 static const size_t PNG_BYTES_TO_CHECK = 4;
00035 
00036 // lbourdev: These can be greatly simplified, for example:
00037 template <typename CS> struct png_color_type {BOOST_STATIC_CONSTANT(int,color_type=0);};
00038 template<> struct png_color_type<gray_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); };
00039 template<> struct png_color_type<rgb_t>  { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); };
00040 template<> struct png_color_type<rgba_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); };
00041 
00042 template <typename CHANNEL,typename COLORSPACE> struct png_is_supported {BOOST_STATIC_CONSTANT(bool,value=false);};
00043 template <> struct png_is_supported<bits8,gray_t>  {BOOST_STATIC_CONSTANT(bool,value=true);};
00044 template <> struct png_is_supported<bits8,rgb_t>   {BOOST_STATIC_CONSTANT(bool,value=true);};
00045 template <> struct png_is_supported<bits8,rgba_t>  {BOOST_STATIC_CONSTANT(bool,value=true);};
00046 template <> struct png_is_supported<bits16,gray_t> {BOOST_STATIC_CONSTANT(bool,value=true);};
00047 template <> struct png_is_supported<bits16,rgb_t>  {BOOST_STATIC_CONSTANT(bool,value=true);};
00048 template <> struct png_is_supported<bits16,rgba_t> {BOOST_STATIC_CONSTANT(bool,value=true);};
00049 
00050 template <typename CHANNEL> struct png_bit_depth {BOOST_STATIC_CONSTANT(int,bit_depth=sizeof(CHANNEL)*8);};
00051 
00052 template <typename CHANNEL,typename COLORSPACE>
00053 struct png_read_support_private {
00054     BOOST_STATIC_CONSTANT(bool,is_supported=false);
00055     BOOST_STATIC_CONSTANT(int,bit_depth=0);
00056     BOOST_STATIC_CONSTANT(int,color_type=0);
00057 };
00058 template <>
00059 struct png_read_support_private<bits8,gray_t> {
00060     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00061     BOOST_STATIC_CONSTANT(int,bit_depth=8);
00062     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
00063 };
00064 template <>
00065 struct png_read_support_private<bits8,rgb_t> {
00066     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00067     BOOST_STATIC_CONSTANT(int,bit_depth=8);
00068     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
00069 };
00070 template <>
00071 struct png_read_support_private<bits8,rgba_t> {
00072     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00073     BOOST_STATIC_CONSTANT(int,bit_depth=8);
00074     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
00075 };
00076 template <>
00077 struct png_read_support_private<bits16,gray_t> {
00078     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00079     BOOST_STATIC_CONSTANT(int,bit_depth=16);
00080     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
00081 };
00082 template <>
00083 struct png_read_support_private<bits16,rgb_t> {
00084     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00085     BOOST_STATIC_CONSTANT(int,bit_depth=16);
00086     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
00087 };
00088 template <>
00089 struct png_read_support_private<bits16,rgba_t> {
00090     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00091     BOOST_STATIC_CONSTANT(int,bit_depth=16);
00092     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
00093 };
00094 
00095 template <typename CHANNEL,typename COLORSPACE>
00096 struct png_write_support_private {
00097     BOOST_STATIC_CONSTANT(bool,is_supported=false);
00098     BOOST_STATIC_CONSTANT(int,bit_depth=0);
00099     BOOST_STATIC_CONSTANT(int,color_type=0);
00100 };
00101 template <>
00102 struct png_write_support_private<bits8,gray_t> {
00103     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00104     BOOST_STATIC_CONSTANT(int,bit_depth=8);
00105     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
00106 };
00107 template <>
00108 struct png_write_support_private<bits8,rgb_t> {
00109     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00110     BOOST_STATIC_CONSTANT(int,bit_depth=8);
00111     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
00112 };
00113 template <>
00114 struct png_write_support_private<bits8,rgba_t> {
00115     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00116     BOOST_STATIC_CONSTANT(int,bit_depth=8);
00117     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
00118 };
00119 template <>
00120 struct png_write_support_private<bits16,gray_t> {
00121     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00122     BOOST_STATIC_CONSTANT(int,bit_depth=16);
00123     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY);
00124 };
00125 template <>
00126 struct png_write_support_private<bits16,rgb_t> {
00127     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00128     BOOST_STATIC_CONSTANT(int,bit_depth=16);
00129     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB);
00130 };
00131 template <>
00132 struct png_write_support_private<bits16,rgba_t> {
00133     BOOST_STATIC_CONSTANT(bool,is_supported=true);
00134     BOOST_STATIC_CONSTANT(int,bit_depth=16);
00135     BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA);
00136 };
00137 
00138 class png_reader : public file_mgr {
00139 protected:
00140     png_structp _png_ptr;
00141     png_infop _info_ptr;
00142 
00143     void init() {
00144         char buf[detail::PNG_BYTES_TO_CHECK];
00145         // read in some of the signature bytes
00146         io_error_if(fread(buf, 1, PNG_BYTES_TO_CHECK, get()) != detail::PNG_BYTES_TO_CHECK,
00147                     "png_check_validity: fail to read file");
00148         // compare the first PNG_BYTES_TO_CHECK bytes of the signature.
00149         io_error_if(png_sig_cmp((png_bytep)buf, (png_size_t)0, detail::PNG_BYTES_TO_CHECK)!=0,
00150                     "png_check_validity: invalid png file");
00151 
00152         _png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
00153         io_error_if(_png_ptr==NULL,"png_get_file_size: fail to call png_create_write_struct()");
00154         // allocate/initialize the image information data
00155         _info_ptr = png_create_info_struct(_png_ptr);
00156         if (_info_ptr == NULL) {
00157             png_destroy_read_struct(&_png_ptr,png_infopp_NULL,png_infopp_NULL);
00158             io_error("png_get_file_size: fail to call png_create_info_struct()");
00159         }
00160         if (setjmp(png_jmpbuf(_png_ptr))) {
00161             //free all of the memory associated with the png_ptr and info_ptr
00162             png_destroy_read_struct(&_png_ptr, &_info_ptr, png_infopp_NULL);
00163             io_error("png_get_file_size: fail to call setjmp()");
00164         }
00165         png_init_io(_png_ptr, get());
00166         png_set_sig_bytes(_png_ptr,PNG_BYTES_TO_CHECK);
00167         png_read_info(_png_ptr, _info_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<int> get_dimensions() {
00177         return point2<int>(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 VIEW::channel_t,
00191                                     typename VIEW::color_space_t::base>::bit_depth!=bit_depth ||
00192            png_read_support_private<typename VIEW::channel_t,
00193                                     typename VIEW::color_space_t::base>::color_type!=color_type)
00194             io_error("png_read_view: input view type is incompatible with the image type");
00195         
00196         typedef typename VIEW::color_space_t::base CS;
00197         typedef typename VIEW::channel_t CH;
00198         std::vector<pixel<CH,CS> > row(width);
00199         for(png_uint_32 y=0;y<height;++y) {
00200             png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
00201             std::copy(row.begin(),row.end(),view.row_begin(y));
00202         }
00203         png_read_end(_png_ptr,NULL);
00204     }
00205 
00206     template <typename IMAGE>
00207     void read_image(IMAGE& im) {
00208         resize_clobber_image(im,get_dimensions());
00209         apply(view(im));
00210     }
00211 };
00212 
00213 // This code will be simplified...
00214 class png_reader_color_convert : public png_reader {
00215 public:
00216     png_reader_color_convert(FILE* file          ) : png_reader(file) {}
00217     png_reader_color_convert(const char* filename) : png_reader(filename) {}
00218     template <typename VIEW>
00219     void apply(const VIEW& view) {
00220         png_uint_32 width, height;
00221         int bit_depth, color_type, interlace_type;
00222         png_get_IHDR(_png_ptr, _info_ptr,
00223                      &width, &height,&bit_depth,&color_type,&interlace_type,
00224                      int_p_NULL, int_p_NULL);
00225         io_error_if(((png_uint_32)view.width()!=width || (png_uint_32)view.height()!= height),
00226                     "png_reader_color_convert::apply(): input view size does not match PNG file size");
00227         switch (color_type) {
00228         case PNG_COLOR_TYPE_GRAY:
00229             switch (bit_depth) {
00230             case 8: {
00231                 std::vector<pixel<bits8,gray_t> > row(width);
00232                 for(png_uint_32 y=0;y<height;++y) {
00233                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
00234                     std::transform(row.begin(),row.end(),view.row_begin(y),
00235                                    color_converter<typename VIEW::pixel_t>());
00236                 }
00237                 break;
00238             }
00239             case 16: {
00240                 std::vector<pixel<bits16,gray_t> > row(width);
00241                 for(png_uint_32 y=0;y<height;++y) {
00242                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
00243                     std::transform(row.begin(),row.end(),view.row_begin(y),
00244                                    color_converter<typename VIEW::pixel_t>());
00245                 }
00246                 break;
00247             }
00248             default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth");
00249             }
00250             break;
00251         case PNG_COLOR_TYPE_RGB:
00252             switch (bit_depth) {
00253             case 8: {
00254                 std::vector<pixel<bits8,rgb_t> > row(width);
00255                 for(png_uint_32 y=0;y<height;++y) {
00256                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
00257                     std::transform(row.begin(),row.end(),view.row_begin(y),
00258                                    color_converter<typename VIEW::pixel_t>());
00259                 }
00260                 break;
00261             }
00262             case 16: {
00263                 std::vector<pixel<bits16,rgb_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),
00267                                    color_converter<typename VIEW::pixel_t>());
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<pixel<bits8,rgba_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),
00281                                    color_converter<typename VIEW::pixel_t>());
00282                 }
00283                 break;
00284             }
00285             case 16: {
00286                 std::vector<pixel<bits16,rgba_t> > row(width);
00287                 for(png_uint_32 y=0;y<height;++y) {
00288                     png_read_row(_png_ptr,(png_bytep)&row.front(),NULL);
00289                     std::transform(row.begin(),row.end(),view.row_begin(y),
00290                                    color_converter<typename VIEW::pixel_t>());
00291                 }
00292                 break;
00293             }
00294             default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth");
00295             }
00296             break;
00297         default: io_error("png_reader_color_convert::apply(): unknown color type");
00298         }
00299         png_read_end(_png_ptr,NULL);
00300     }
00301     template <typename IMAGE>
00302     void read_image(IMAGE& im) {
00303         resize_clobber_image(im,get_dimensions());
00304         apply(view(im));
00305     }
00306 };
00307 
00308 
00309 class png_writer : public file_mgr {
00310 protected:
00311     png_structp _png_ptr;
00312     png_infop _info_ptr;
00313 
00314     void init() {
00315         _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
00316         io_error_if(!_png_ptr,"png_write_initialize: fail to call png_create_write_struct()");
00317         _info_ptr = png_create_info_struct(_png_ptr);
00318         if (!_info_ptr) {
00319             png_destroy_write_struct(&_png_ptr,png_infopp_NULL);
00320             io_error("png_write_initialize: fail to call png_create_info_struct()");
00321         }
00322         if (setjmp(png_jmpbuf(_png_ptr))) {
00323             png_destroy_write_struct(&_png_ptr, &_info_ptr);
00324             io_error("png_write_initialize: fail to call setjmp(png_jmpbuf())");
00325         }
00326         png_init_io(_png_ptr,get());
00327     }
00328 public:
00329     png_writer(FILE* file          ) : file_mgr(file)           { init(); }
00330     png_writer(const char* filename) : file_mgr(filename, "wb") { init(); }
00331 
00332     ~png_writer() {
00333         png_destroy_write_struct(&_png_ptr,&_info_ptr);
00334     }
00335     template <typename VIEW>
00336     void apply(const VIEW& view) {
00337         png_set_IHDR(_png_ptr, _info_ptr, view.width(), view.height(),
00338                      png_write_support_private<typename VIEW::channel_t,
00339                                                typename VIEW::color_space_t::base>::bit_depth,
00340                      png_write_support_private<typename VIEW::channel_t,
00341                                                typename VIEW::color_space_t::base>::color_type,
00342                      PNG_INTERLACE_NONE,
00343                      PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
00344         png_write_info(_png_ptr,_info_ptr);
00345         typedef typename VIEW::color_space_t::base CS;
00346         typedef typename VIEW::channel_t CH;
00347         std::vector<pixel<CH,CS> > 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 ADOBE_GIL_NAMESPACE_END
00358 
00359 #endif

Copyright © 2006 Adobe Systems Incorporated.

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

Search powered by Google