34 #define ERR_NO_ERROR 0
38 #define ERR_OPEN_WRITE 4
39 #define ERR_PNGLIB_WRITE 5
40 #define ERR_MEM_WRITE 6
45 static jmp_buf setjmp_buffer;
49 warn_callback(png_structp ps, png_const_charp pc)
56 err_callback(png_structp ps, png_const_charp pc)
61 longjmp(setjmp_buffer, 1);
69 strncpy(buffer,
"PNG loader: Error opening file", buflen);
72 strncpy(buffer,
"PNG loader: Out of memory error", buflen);
75 strncpy(buffer,
"PNG loader: Illegal png file", buflen);
78 strncpy(buffer,
"PNG saver: Error opening file", buflen);
80 case ERR_PNGLIB_WRITE:
81 strncpy(buffer,
"PNG saver: Internal libpng error", buflen);
84 strncpy(buffer,
"PNG saver: Out of memory error", buflen);
93 const unsigned char *header,
96 static unsigned char pngcmp[] = {0x89,
'P',
'N',
'G', 0xd, 0xa, 0x1a, 0xa};
97 if (headerlen < 8)
return 0;
98 if (memcmp((
const void*)header,
99 (
const void*)pngcmp, 8) == 0)
return 1;
106 user_read_cb(png_structp png_ptr, png_bytep data, png_uint_32 length)
108 int readlen = (int) fread(data, 1, length, (FILE *)png_get_io_ptr(png_ptr));
109 if (readlen != length) {
116 user_write_cb(png_structp png_ptr, png_bytep data, png_uint_32 length)
118 int writelen = (int) fwrite(data, 1, length, (FILE *)png_get_io_ptr(png_ptr));
119 if (writelen != length) {
126 user_flush_cb(png_structp png_ptr)
128 int err = fflush((FILE *)png_get_io_ptr(png_ptr));
138 int *numComponents_ret)
142 png_uint_32 width, height;
144 int bit_depth, color_type, interlace_type;
146 unsigned char *buffer;
147 int y, bytes_per_row;
150 png_bytepp row_pointers;
152 if ((fp = fopen(filename,
"rb")) == NULL) {
166 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
167 NULL, err_callback, warn_callback);
169 if (png_ptr == NULL) {
176 info_ptr = png_create_info_struct(png_ptr);
177 if (info_ptr == NULL) {
180 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
191 if (setjmp(setjmp_buffer)) {
192 pngerror = ERR_PNGLIB;
194 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
198 if (buffer) free(buffer);
205 png_set_read_fn(png_ptr, (
void *)fp, (png_rw_ptr)user_read_cb);
210 png_read_info(png_ptr, info_ptr);
212 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
213 &interlace_type, NULL, NULL);
222 png_set_strip_16(png_ptr);
238 if (color_type == PNG_COLOR_TYPE_PALETTE)
239 png_set_expand(png_ptr);
242 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
243 png_set_expand(png_ptr);
247 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
248 png_set_expand(png_ptr);
253 png_read_update_info(png_ptr, info_ptr);
255 channels = png_get_channels(png_ptr, info_ptr);
259 bytes_per_row = png_get_rowbytes(png_ptr, info_ptr);
262 buffer = (
unsigned char*) malloc((
size_t)bytes_per_row*height);
266 row_pointers = (png_bytepp) malloc(height*
sizeof(png_bytep));
267 for (y = 0; y < height; y++) {
268 row_pointers[height-y-1] = buffer + y*bytes_per_row;
271 png_read_image(png_ptr, row_pointers);
272 png_read_end(png_ptr, info_ptr);
277 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
285 *height_ret = height;
286 *numComponents_ret = format;
297 const unsigned char * bytes,
307 #ifdef PNG_TEXT_SUPPORTED
308 png_text text_ptr[3];
312 fp = fopen(filename,
"wb");
324 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
327 if (png_ptr == NULL) {
334 info_ptr = png_create_info_struct(png_ptr);
335 if (info_ptr == NULL) {
337 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
338 pngerror = ERR_MEM_WRITE;
345 #if PNG_LIBPNG_VER < 10400
346 if (setjmp(png_ptr->jmpbuf)) {
348 if (setjmp(png_jmpbuf(png_ptr))) {
352 png_destroy_write_struct(&png_ptr, (png_infopp)info_ptr);
353 pngerror = ERR_PNGLIB_WRITE;
360 png_set_write_fn(png_ptr, (
void *)fp, (png_rw_ptr)user_write_cb,
361 (png_flush_ptr)user_flush_cb);
372 switch (numcomponents) {
374 colortype = PNG_COLOR_TYPE_GRAY;
377 colortype = PNG_COLOR_TYPE_GRAY_ALPHA;
380 colortype = PNG_COLOR_TYPE_RGB;
384 colortype = PNG_COLOR_TYPE_RGB_ALPHA;
388 png_set_IHDR(png_ptr, info_ptr, width, height, 8, colortype,
389 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
395 #if defined(PNG_TEXT_SUPPORTED)
397 text_ptr[0].key =
"Title";
398 text_ptr[0].text = (
char*)filename;
399 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
400 text_ptr[1].key =
"Author";
401 text_ptr[1].text =
"simage (https://coin3d.github.io)";
402 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
403 text_ptr[2].key =
"Description";
404 text_ptr[2].text =
"Image saved using simage.";
405 text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
406 png_set_text(png_ptr, info_ptr, text_ptr, 3);
412 png_write_info(png_ptr, info_ptr);
457 bytesperrow = width * numcomponents;
459 for (y = 0; y < height; y++) {
460 png_write_row(png_ptr, (png_bytep) bytes + bytesperrow * (height-y-1));
468 png_write_end(png_ptr, info_ptr);
473 png_destroy_write_struct(&png_ptr, &info_ptr);
int simage_png_identify(const char *filename, const unsigned char *header, int headerlen)
int simage_png_error(char *buffer, int bufferlen)
unsigned char * simage_png_load(const char *filename, int *width, int *height, int *numComponents)
int simage_png_save(const char *filename, const unsigned char *bytes, int width, int height, int numcomponents)