1 //metadoc PNGImage copyright Steve Dekorte 2002
2 //metadoc PNGImage license BSD revised
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();
26 PNGImage
*PNGImage_newWithPath_(char *path
)
28 PNGImage
*self
= PNGImage_new();
29 PNGImage_path_(self
, path
);
34 void PNGImage_free(PNGImage
*self
)
36 if (self
->ownsBuffer
) UArray_free(self
->byteArray
);
37 if (self
->error
) free(self
->error
);
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
)
64 int palleteComponents
= 3;
66 int number_passes
, row
;
67 FILE *fp
= fopen(self
->path
, "rb");
68 PNGImage_error_(self
, "");
72 PNGImage_error_(self
, "file not found");
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
);
87 PNGImage_error_(self
, "unable to read png from file");
91 /* Allocate/initialize the memory for image information. REQUIRED. */
92 info_ptr
= png_create_info_struct(png_ptr
);
97 png_destroy_read_struct(&(png_ptr
), png_infopp_NULL
, png_infopp_NULL
);
98 PNGImage_error_(self
, "error allocating png struct");
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
);
112 PNGImage_error_(self
, self
->path
);
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
);
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
);
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
]);
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
);
224 void PNGImage_save(PNGImage
*self
)
229 /*png_colorp palette;*/
232 fp
= fopen(self
->path
, "wb");
236 PNGImage_error_(self
, "unable to open file");
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
);
251 PNGImage_error_(self
, "unable to create png struct");
255 /* Allocate/initialize the image information data. REQUIRED */
256 info_ptr
= png_create_info_struct(png_ptr
);
258 if (info_ptr
== NULL
)
261 png_destroy_write_struct(&png_ptr
, png_infopp_NULL
);
262 PNGImage_error_(self
, "unable to create png struct");
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 */
273 png_destroy_write_struct(&png_ptr
, &info_ptr
);
274 PNGImage_error_(self
, "problem writing file");
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; }
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;
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);
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
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() */
410 number_passes = png_set_interlace_handling(png_ptr);
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.
421 png_bytep
*row_pointers
= malloc(self
->height
*sizeof(png_bytep
*)); // JEFF DRAKE MOD: YOU CAN'T HAVE A NON-CONSTANT
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
);
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
450 png_free(png_ptr, palette);
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);
462 /* clean up after the write, and free any memory allocated */
463 png_destroy_write_struct(&png_ptr
, &info_ptr
);
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
;
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;