00001
00002
00003
00004
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
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
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
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
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
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
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 }
00357 ADOBE_GIL_NAMESPACE_END
00358
00359 #endif