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

Generated on Sat May 2 13:50:15 2009 for Generic Image Library by  doxygen 1.5.6