00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00033
00034 #ifndef GROOVX_MEDIA_PNGPARSER_CC_UTC20050626084018_DEFINED
00035 #define GROOVX_MEDIA_PNGPARSER_CC_UTC20050626084018_DEFINED
00036
00037 #include "pngparser.h"
00038
00039 #ifndef HAVE_LIBPNG
00040
00041 #include "rutz/error.h"
00042
00043 void media::load_png(const char* , media::bmap_data& )
00044 {
00045 throw rutz::error("png image files are not supported in this build",
00046 SRC_POS);
00047 }
00048
00049 void media::save_png(const char* , const media::bmap_data& )
00050 {
00051 throw rutz::error("png image files are not supported in this build",
00052 SRC_POS);
00053 }
00054
00055 #else
00056
00057 #include "geom/vec2.h"
00058
00059 #include "media/bmapdata.h"
00060
00061 #include "rutz/arrays.h"
00062 #include "rutz/error.h"
00063 #include "rutz/sfmt.h"
00064
00065 #include <cstdio>
00066 #include <png.h>
00067
00068 #include "rutz/debug.h"
00069 GVX_DBG_REGISTER
00070 #include "rutz/trace.h"
00071
00072 namespace
00073 {
00075
00078 class png_parser
00079 {
00080 public:
00081 png_parser() :
00082 m_file(0),
00083 m_png_ptr(0),
00084 m_info_ptr(0),
00085 m_end_ptr(0)
00086 {}
00087
00088 ~png_parser() { close(); }
00089
00090 void close();
00091
00092 void parse(const char* filename, media::bmap_data& data);
00093
00094 private:
00095 png_parser(const png_parser&);
00096 png_parser& operator=(const png_parser&);
00097
00098 FILE* m_file;
00099 png_structp m_png_ptr;
00100 png_infop m_info_ptr;
00101 png_infop m_end_ptr;
00102 };
00103
00104 void png_parser::close()
00105 {
00106 GVX_TRACE("png_parser::close");
00107 if (m_png_ptr != 0)
00108 {
00109 png_destroy_read_struct(m_png_ptr ? &m_png_ptr : 0,
00110 m_info_ptr ? &m_info_ptr : 0,
00111 m_end_ptr ? &m_end_ptr : 0);
00112 }
00113
00114 if (m_file != 0)
00115 {
00116 fclose(m_file);
00117 m_file = 0;
00118 }
00119 }
00120
00121 void png_parser::parse(const char* filename, media::bmap_data& data)
00122 {
00123 GVX_TRACE("png_parser::parse");
00124 m_file = fopen(filename, "rb");
00125 if (m_file == 0)
00126 {
00127 throw rutz::error("couldn't open file for png reading", SRC_POS);
00128 }
00129
00130 const int nheader = 8;
00131 png_byte header[nheader];
00132
00133 fread(header, 1, nheader, m_file);
00134
00135 int is_png = !png_sig_cmp(header, 0, nheader);
00136 if (!is_png)
00137 {
00138 throw rutz::error(rutz::sfmt("%s is not a PNG image file",
00139 filename),
00140 SRC_POS);
00141 }
00142
00143 m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00144 if (m_png_ptr == 0)
00145 throw rutz::error("PNG library couldn't create read_struct",
00146 SRC_POS);
00147
00148 m_info_ptr = png_create_info_struct(m_png_ptr);
00149 if (m_info_ptr == 0)
00150 {
00151 throw rutz::error("PNG library couldn't create info_struct",
00152 SRC_POS);
00153 }
00154
00155 m_end_ptr = png_create_info_struct(m_png_ptr);
00156 if (m_end_ptr == 0)
00157 {
00158 throw rutz::error("PNG library couldn't create end info_struct",
00159 SRC_POS);
00160 }
00161
00162 png_init_io(m_png_ptr, m_file);
00163
00164 png_set_sig_bytes(m_png_ptr, nheader);
00165
00166 png_read_info(m_png_ptr, m_info_ptr);
00167
00168 const int bit_depth = png_get_bit_depth(m_png_ptr, m_info_ptr);
00169
00170 switch (bit_depth)
00171 {
00172 case 16:
00173
00174 png_set_strip_16(m_png_ptr);
00175 break;
00176
00177 case 8:
00178
00179 break;
00180
00181 case 4:
00182 case 2:
00183 case 1:
00184
00185 png_set_packing(m_png_ptr);
00186 break;
00187
00188 default:
00189 throw rutz::error(rutz::sfmt("bit-depth '%d' is not supported "
00190 "for PNG images "
00191 "(must be 8- or 16-bit)",
00192 bit_depth),
00193 SRC_POS);
00194 }
00195
00196 const png_byte color_type = png_get_color_type(m_png_ptr, m_info_ptr);
00197
00198 if (color_type & PNG_COLOR_MASK_ALPHA)
00199 png_set_strip_alpha(m_png_ptr);
00200
00201 if (color_type & PNG_COLOR_MASK_PALETTE)
00202 png_set_palette_to_rgb(m_png_ptr);
00203
00204
00205 png_read_update_info(m_png_ptr, m_info_ptr);
00206
00207
00208
00209 const int width = png_get_image_width(m_png_ptr, m_info_ptr);
00210 const int height = png_get_image_height(m_png_ptr, m_info_ptr);
00211
00212 dbg_eval(3, width); dbg_eval_nl(3, height);
00213
00214 const int row_bytes = png_get_rowbytes(m_png_ptr, m_info_ptr);
00215
00216 dbg_eval_nl(3, row_bytes);
00217
00218 const int nchannels = png_get_channels(m_png_ptr, m_info_ptr);
00219
00220 dbg_eval_nl(3, nchannels);
00221
00222 GVX_ASSERT(row_bytes == width*nchannels);
00223
00224 media::bmap_data new_data(geom::vec2<int>(width, height),
00225 nchannels*8,
00226 1);
00227
00228 rutz::fixed_block<png_bytep> row_pointers(height);
00229
00230 for (int i = 0; i < height; ++i)
00231 {
00232 row_pointers[i] = (png_bytep) (new_data.row_ptr(i));
00233 }
00234
00235 png_read_image(m_png_ptr, &row_pointers[0]);
00236
00237 png_read_end(m_png_ptr, m_end_ptr);
00238
00239 data.swap(new_data);
00240
00241 this->close();
00242 }
00243
00244 class png_writer
00245 {
00246 public:
00247 png_writer() :
00248 m_file(0),
00249 m_png_ptr(0),
00250 m_info_ptr(0)
00251 {}
00252
00253 ~png_writer() { close(); }
00254
00255 void close();
00256
00257 void write(const char* filename, const media::bmap_data& data);
00258
00259 private:
00260 png_writer(const png_writer&);
00261 png_writer& operator=(const png_writer&);
00262
00263 FILE* m_file;
00264 png_structp m_png_ptr;
00265 png_infop m_info_ptr;
00266 };
00267
00268 void png_writer::close()
00269 {
00270 GVX_TRACE("png_writer::close");
00271 if (m_png_ptr != 0)
00272 {
00273 png_destroy_write_struct(m_png_ptr ? &m_png_ptr : 0,
00274 m_info_ptr ? &m_info_ptr : 0);
00275 }
00276
00277 if (m_file != 0)
00278 {
00279 fclose(m_file);
00280 m_file = 0;
00281 }
00282 }
00283
00284 int get_color_type(const media::bmap_data& data)
00285 {
00286 switch (data.bits_per_pixel())
00287 {
00288 case 1: return PNG_COLOR_TYPE_GRAY;
00289 case 8: return PNG_COLOR_TYPE_GRAY;
00290 case 24: return PNG_COLOR_TYPE_RGB;
00291 case 32: return PNG_COLOR_TYPE_RGB_ALPHA;
00292 default:
00293 throw rutz::error(rutz::sfmt("invalid bits_per_pixel value: %d",
00294 data.bits_per_pixel()), SRC_POS);
00295 }
00296 return 0;
00297 }
00298
00299 void png_writer::write(const char* filename,
00300 const media::bmap_data& data)
00301 {
00302 GVX_TRACE("png_writer::write");
00303
00304 m_file = fopen(filename, "wb");
00305 if (m_file == 0)
00306 {
00307 throw rutz::error(rutz::sfmt("couldn't open file '%s' for "
00308 "png writing", filename), SRC_POS);
00309 }
00310
00311 m_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00312 if (m_png_ptr == 0)
00313 throw rutz::error("PNG library couldn't create write_struct",
00314 SRC_POS);
00315
00316 m_info_ptr = png_create_info_struct(m_png_ptr);
00317 if (m_info_ptr == 0)
00318 {
00319 throw rutz::error("PNG library couldn't create info_struct",
00320 SRC_POS);
00321 }
00322
00323 png_init_io(m_png_ptr, m_file);
00324
00325 png_set_compression_level(m_png_ptr, 7);
00326
00327 png_set_IHDR(m_png_ptr, m_info_ptr,
00328 data.width(), data.height(),
00329 data.bits_per_component(),
00330 get_color_type(data),
00331 PNG_INTERLACE_NONE,
00332 PNG_COMPRESSION_TYPE_DEFAULT,
00333 PNG_FILTER_TYPE_DEFAULT);
00334
00335 png_write_info(m_png_ptr, m_info_ptr);
00336
00337 const int height = data.height();
00338
00339 rutz::fixed_block<png_bytep> row_pointers(height);
00340
00341 for (int i = 0; i < height; ++i)
00342 {
00343 row_pointers[i] = static_cast<png_bytep>(data.row_ptr(i));
00344 }
00345
00346 png_write_image(m_png_ptr, &row_pointers[0]);
00347 png_write_end(m_png_ptr, m_info_ptr);
00348
00349 this->close();
00350 }
00351
00352 }
00353
00354 void media::load_png(const char* filename, media::bmap_data& data)
00355 {
00356 GVX_TRACE("media::load_png");
00357 png_parser parser;
00358
00359 parser.parse(filename, data);
00360 }
00361
00362 void media::save_png(const char* filename, const media::bmap_data& data)
00363 {
00364 GVX_TRACE("media::save_png");
00365 png_writer writer;
00366
00367 writer.write(filename, data);
00368 }
00369
00370 #endif // HAVE_LIBPNG
00371
00372 static const char __attribute__((used)) vcid_groovx_media_pngparser_cc_utc20050626084018[] = "$Id: pngparser.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00373 #endif // !GROOVX_MEDIA_PNGPARSER_CC_UTC20050626084018_DEFINED