Addons updated to new doc format
[io.git] / addons / Image / source / PNGImage.c
blob58ba68647576f56d62fb1d0683812f996a41687a
1 //metadoc PNGImage copyright Steve Dekorte 2002
2 //metadoc PNGImage license BSD revised
4 #include "PNGImage.h"
5 #include <png.h>
7 #include <stdio.h>
8 #include <stdlib.h>
10 #ifndef _WIN32
11 #include <unistd.h>
12 #endif
14 #include <string.h>
16 PNGImage *PNGImage_new(void)
18 PNGImage *self = (PNGImage *)calloc(1, sizeof(PNGImage));
19 PNGImage_path_(self, "");
20 PNGImage_error_(self, "");
21 self->byteArray = UArray_new();
22 self->ownsBuffer = 1;
23 return self;
26 PNGImage *PNGImage_newWithPath_(char *path)
28 PNGImage *self = PNGImage_new();
29 PNGImage_path_(self, path);
30 PNGImage_load(self);
31 return self;
34 void PNGImage_free(PNGImage *self)
36 if (self->ownsBuffer) UArray_free(self->byteArray);
37 if (self->error) free(self->error);
38 free(self->path);
39 free(self);
42 void PNGImage_path_(PNGImage *self, const char *path)
43 { self->path = strcpy((char *)realloc(self->path, strlen(path)+1), path); }
45 char *PNGImage_path(PNGImage *self) { return self->path; }
47 void PNGImage_error_(PNGImage *self, const char *error)
49 self->error = strcpy((char *)realloc(self->error, strlen(error)+1), error);
50 /*if (strlen(self->error)) printf("PNGImage error: %s\n", self->error);*/
53 char *PNGImage_error(PNGImage *self) { return self->error; }
55 void PNGImage_load(PNGImage *self)
57 png_structp png_ptr;
58 png_infop info_ptr;
59 int bit_depth;
60 int color_type;
61 int interlace_type;
62 png_uint_32 w;
63 png_uint_32 h;
64 int palleteComponents = 3;
66 int number_passes, row;
67 FILE *fp = fopen(self->path, "rb");
68 PNGImage_error_(self, "");
70 if (!fp)
72 PNGImage_error_(self, "file not found");
73 return;
76 /* Create and initialize the png_struct with the desired error handler
77 * functions. If you want to use the default stderr and longjump method,
78 * you can supply NULL for the last three parameters. We also supply the
79 * the compiler header file version, so that we know if the application
80 * was compiled with a compatible version of the library. REQUIRED
82 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
84 if (png_ptr == NULL)
86 fclose(fp);
87 PNGImage_error_(self, "unable to read png from file");
88 return;
91 /* Allocate/initialize the memory for image information. REQUIRED. */
92 info_ptr = png_create_info_struct(png_ptr);
94 if (info_ptr == NULL)
96 fclose(fp);
97 png_destroy_read_struct(&(png_ptr), png_infopp_NULL, png_infopp_NULL);
98 PNGImage_error_(self, "error allocating png struct");
99 return;
102 /* Set error handling if you are using the setjmp/longjmp method (this is
103 * the normal method of doing things with libpng). REQUIRED unless you
104 * set up your own error handlers in the png_create_read_struct() earlier.
107 if (setjmp(png_jmpbuf(png_ptr)))
109 /* Free all of the memory associated with the png_ptr and info_ptr */
110 png_destroy_read_struct(&(png_ptr), &(info_ptr), png_infopp_NULL);
111 fclose(fp);
112 PNGImage_error_(self, self->path);
113 return;
116 /* Set up the input control if you are using standard C streams */
117 png_init_io(png_ptr, fp);
118 png_read_info(png_ptr, info_ptr);
120 png_get_IHDR(png_ptr, info_ptr, &w, &h, &(bit_depth),
121 &(color_type), &(interlace_type), int_p_NULL, int_p_NULL);
123 self->width = w;
124 self->height = h;
126 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
127 png_set_strip_16(png_ptr);
130 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
131 * byte into separate bytes (useful for paletted and grayscale images).
133 png_set_packing(png_ptr);
135 /* Expand paletted colors into true RGB triplets */
137 if (color_type == PNG_COLOR_TYPE_PALETTE)
138 png_set_palette_rgb(png_ptr);
141 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
142 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
143 png_set_gray_1_2_4_to_8(png_ptr);
145 /* Expand paletted or RGB images with transparency to full alpha channels
146 * so the data will be available as RGBA quartets.
148 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
150 png_set_tRNS_to_alpha(png_ptr);
151 palleteComponents = 4;
154 /* swap bytes of 16 bit files to least significant byte first */
155 /*png_set_swap(png_ptr);*/
157 /* Add filler (or alpha) byte (before/after each RGB triplet) */
158 /*png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);*/
160 /* Turn on interlace handling. REQUIRED if you are not using
161 * png_read_image(). To see how to handle interlacing passes,
162 * see the png_read_row() method below:
164 number_passes = png_set_interlace_handling(png_ptr);
166 /* Allocate the memory to hold the image using the fields of info_ptr. */
168 /* The easiest way to read the image: */
170 /*png_bytep row_pointers[height];*/
171 png_bytep *row_pointers = (png_bytep *)malloc(self->height*sizeof(void *));
173 for (row = 0; row < self->height; row++)
175 /*int bpr = png_get_rowbytes(png_ptr, info_ptr);*/
176 int bpr = png_get_rowbytes(png_ptr, info_ptr) * 4;
177 row_pointers[row] = png_malloc(png_ptr, bpr);
180 /* Now it's time to read the image. One of these methods is REQUIRED */
181 png_read_image(png_ptr, row_pointers);
184 int bytesPerRow;
185 switch(color_type)
187 case PNG_COLOR_TYPE_GRAY:
188 self->components = 1; break;
189 case PNG_COLOR_TYPE_PALETTE:
190 self->components = palleteComponents; break;
191 case PNG_COLOR_TYPE_RGB:
192 self->components = 3; break;
193 case PNG_COLOR_TYPE_RGB_ALPHA:
194 self->components = 4; break;
195 case PNG_COLOR_TYPE_GRAY_ALPHA:
196 self->components = 2; break;
199 bytesPerRow = self->width * self->components;
200 UArray_setSize_(self->byteArray, self->width * self->height * self->components);
202 for (row = 0; row < self->height; row++)
204 int i = row*(self->width*self->components);
205 memcpy((uint8_t *)UArray_bytes(self->byteArray) + i, row_pointers[row], bytesPerRow);
206 free(row_pointers[row]);
210 free(row_pointers);
212 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
213 png_read_end(png_ptr, (info_ptr));
215 /* At this point you have read the entire image */
217 /* clean up after the read, and free any memory allocated - REQUIRED */
218 png_destroy_read_struct(&(png_ptr), &(info_ptr), png_infopp_NULL);
220 fclose(fp);
221 return;
224 void PNGImage_save(PNGImage *self)
226 FILE *fp;
227 png_structp png_ptr;
228 png_infop info_ptr;
229 /*png_colorp palette;*/
231 /* open the file */
232 fp = fopen(self->path, "wb");
234 if (fp == NULL)
236 PNGImage_error_(self, "unable to open file");
237 return;
240 /* Create and initialize the png_struct with the desired error handler
241 * functions. If you want to use the default stderr and longjump method,
242 * you can supply NULL for the last three parameters. We also check that
243 * the library version is compatible with the one used at compile time,
244 * in case we are using dynamically linked libraries. REQUIRED.
246 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
248 if (png_ptr == NULL)
250 fclose(fp);
251 PNGImage_error_(self, "unable to create png struct");
252 return;
255 /* Allocate/initialize the image information data. REQUIRED */
256 info_ptr = png_create_info_struct(png_ptr);
258 if (info_ptr == NULL)
260 fclose(fp);
261 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
262 PNGImage_error_(self, "unable to create png struct");
263 return;
266 /* Set error handling. REQUIRED if you aren't supplying your own
267 * error handling functions in the png_create_write_struct() call.
269 if (setjmp(png_jmpbuf(png_ptr)))
271 /* If we get here, we had a problem reading the file */
272 fclose(fp);
273 png_destroy_write_struct(&png_ptr, &info_ptr);
274 PNGImage_error_(self, "problem writing file");
275 return;
278 /* One of the following I/O initialization functions is REQUIRED */
279 /* set up the output control if you are using standard C streams */
280 png_init_io(png_ptr, fp);
284 /* Set the image information here. Width and height are up to 2^31,
285 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
286 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
287 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
288 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
289 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
290 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
292 png_set_IHDR(png_ptr, info_ptr, self->width, self->height, 8, PNGImage_pngColorType(self),
293 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
295 /* set the palette if there is one. REQUIRED for indexed-color images */
296 /*palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));*/
297 /* ... set palette colors ... */
298 /*png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);*/
299 /* You must not free palette here, because png_set_PLTE only makes a link to
300 the palette that you malloced. Wait until you are about to destroy
301 the png structure. */
303 /* optional significant bit chunk */
304 /* if we are dealing with a grayscale image then */
306 if (self->components < 3)
307 { sig_bit.gray = true_bit_depth; }
308 else
310 /* otherwise, if we are dealing with a color image then */
313 sig_bit.red = true_red_bit_depth;
314 sig_bit.green = true_green_bit_depth;
315 sig_bit.blue = true_blue_bit_depth;
318 /* if the image has an alpha channel then */
320 if (self->components == 2 || self->components = 4)
322 sig_bit.alpha = true_alpha_bit_depth;
323 png_set_sBIT(png_ptr, info_ptr, sig_bit);
327 /* Optional gamma chunk is strongly suggested if you have any guess
328 * as to the correct gamma of the image.
330 /*png_set_gAMA(png_ptr, info_ptr, gamma);*/
332 /* Optionally write comments into the image */
334 text_ptr[0].key = "Title";
335 text_ptr[0].text = "Mona Lisa";
336 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
337 text_ptr[1].key = "Author";
338 text_ptr[1].text = "Leonardo DaVinci";
339 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
340 text_ptr[2].key = "Description";
341 text_ptr[2].text = "<long text>";
342 text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
343 #ifdef PNG_iTXt_SUPPORTED
344 text_ptr[0].lang = NULL;
345 text_ptr[1].lang = NULL;
346 text_ptr[2].lang = NULL;
347 #endif
348 png_set_text(png_ptr, info_ptr, text_ptr, 3);
351 /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
352 /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
353 * on read and must be written in accordance with the sRGB profile */
355 /* Write the file header information. REQUIRED */
356 png_write_info(png_ptr, info_ptr);
358 /* If you want, you can write the info in two steps, in case you need to
359 * write your private chunk ahead of PLTE:
361 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
362 * write_my_chunk();
363 * png_write_info(png_ptr, info_ptr);
365 * However, given the level of known- and unknown-chunk support in 1.1.0
366 * and up, this should no longer be necessary.
369 /* Once we write out the header, the compression type on the text
370 * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
371 * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
372 * at the end.
375 /* set up the transformations you want. Note that these are
376 * all optional. Only call them if you want them.
379 /* invert monochrome pixels */
380 /*png_set_invert_mono(png_ptr);*/
382 /* Shift the pixels up to a legal bit depth and fill in
383 * as appropriate to correctly scale the image.
385 /*png_set_shift(png_ptr, &sig_bit);*/
387 /* pack pixels into bytes */
388 /*png_set_packing(png_ptr);*/
390 /* swap location of alpha bytes from ARGB to RGBA */
391 /*png_set_swap_alpha(png_ptr);*/
393 /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
394 * RGB (4 channels -> 3 channels). The second parameter is not used.
396 /*png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);*/
398 /* flip BGR pixels to RGB */
399 /*png_set_bgr(png_ptr);*/
401 /* swap bytes of 16-bit files to most significant byte first */
402 /*png_set_swap(png_ptr);*/
404 /* swap bits of 1, 2, 4 bit packed pixel formats */
405 /*png_set_packswap(png_ptr);*/
407 /* turn on interlace handling if you are not using png_write_image() */
409 if (interlacing)
410 number_passes = png_set_interlace_handling(png_ptr);
411 else
412 number_passes = 1;
415 /* The easiest way to write the image (you may have a different memory
416 * layout, however, so choose what fits your needs best). You need to
417 * use the first method if you aren't handling interlacing yourself.
420 png_uint_32 k;
421 png_bytep *row_pointers = malloc(self->height*sizeof(png_bytep *)); // JEFF DRAKE MOD: YOU CAN'T HAVE A NON-CONSTANT
422 // ARRAY HERE!!!!
423 for (k = 0; k < (png_uint_32)self->height; k++)
425 /*row_pointers[k] = UArray_bytes(self->byteArray) + k * self->width * 8 * self->components;*/
426 row_pointers[k] = (uint8_t *)UArray_bytes(self->byteArray) + k * self->width * self->components;
429 /* write out the entire image data in one call */
430 png_write_image(png_ptr, row_pointers);
431 free(row_pointers);
434 /* You can write optional chunks like tEXt, zTXt, and tIME at the end
435 * as well. Shouldn't be necessary in 1.1.0 and up as all the public
436 * chunks are supported and you can use png_set_unknown_chunks() to
437 * register unknown chunks into the info structure to be written out.
440 /* It is REQUIRED to call this to finish writing the rest of the file */
441 png_write_end(png_ptr, info_ptr);
442 /*png_write_IEND(png_ptr);*/
444 /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
445 as recommended in versions 1.0.5m and earlier of this example; if
446 libpng mallocs info_ptr->palette, libpng will free it). If you
447 allocated it with malloc() instead of png_malloc(), use free() instead
448 of png_free(). */
450 png_free(png_ptr, palette);
451 palette=NULL;
454 /* Similarly, if you png_malloced any data that you passed in with
455 png_set_something(), such as a hist or trans array, free it here,
456 when you can be sure that libpng is through with it. */
458 png_free(png_ptr, trans);
459 trans=NULL;
462 /* clean up after the write, and free any memory allocated */
463 png_destroy_write_struct(&png_ptr, &info_ptr);
465 /* close the file */
466 fclose(fp);
470 void PNGImage_setBuffer_length_(PNGImage *self, void *data, int size)
471 { self->data = png_create( self->width, self->height, self->format); }
474 int PNGImage_width(PNGImage *self) { return self->width; }
475 int PNGImage_height(PNGImage *self) { return self->height; }
477 void PNGImage_width_(PNGImage *self, int w) { self->width = w; }
478 void PNGImage_height_(PNGImage *self, int h) { self->height = h; }
479 void PNGImage_components_(PNGImage *self, int c) { self->components = c; }
481 int PNGImage_pngColorType(PNGImage *self)
483 switch (self->components)
485 case 1: return PNG_COLOR_TYPE_GRAY;
486 case 2: return PNG_COLOR_TYPE_GRAY_ALPHA;
487 case 3: return PNG_COLOR_TYPE_RGB;
488 case 4: return PNG_COLOR_TYPE_RGBA;
490 return -1;
493 unsigned char PNGImage_isL8(PNGImage *self) { return (self->components == 1); }
494 unsigned char PNGImage_isLA8(PNGImage *self) { return (self->components == 2); }
495 unsigned char PNGImage_isRGB8(PNGImage *self) { return (self->components == 3); }
496 unsigned char PNGImage_isRGBA8(PNGImage *self) { return (self->components == 4); }
498 int PNGImage_components(PNGImage *self)
500 return self->components;
503 int PNGImage_sizeInBytes(PNGImage *self)
505 return self->height * self->width * self->components;
508 void *PNGImage_data(PNGImage *self)
510 return (uint8_t *)UArray_bytes(self->byteArray);
513 UArray *PNGImage_byteArray(PNGImage *self)
515 return self->byteArray;
518 void PNGImage_setExternalUArray_(PNGImage *self, UArray *ba)
520 if (self->ownsBuffer) UArray_free(self->byteArray);
521 self->byteArray = ba;
522 self->ownsBuffer = 0;