00001
00002
00003
00004
00005
00006
00007
00008
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
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
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
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
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
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
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 }
00357 } }
00358
00359 #endif