4 /* this is a way to get number of channels from color space
5 * Color code to channel number */
7 static int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
9 #define PNG_BYTES_TO_CHECK 4
12 read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
15 read_direct16(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
18 read_paletted(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
21 read_bilevel(png_structp png_ptr, png_infop info_ptr, i_img_dim width, i_img_dim height);
24 i_png_lib_version(void) {
25 return png_access_version_number();
29 wiol_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
30 io_glue *ig = png_get_io_ptr(png_ptr);
31 ssize_t rc = i_io_read(ig, data, length);
32 if (rc != length) png_error(png_ptr, "Read overflow error on an iolayer source.");
36 wiol_write_data(png_structp png_ptr, png_bytep data, png_size_t length) {
38 io_glue *ig = png_get_io_ptr(png_ptr);
39 rc = i_io_write(ig, data, length);
40 if (rc != length) png_error(png_ptr, "Write error on an iolayer source.");
44 wiol_flush_data(png_structp png_ptr) {
45 /* XXX : This needs to be added to the io layer */
49 error_handler(png_structp png_ptr, png_const_charp msg) {
50 mm_log((1, "PNG error: '%s'\n", msg));
53 longjmp(png_jmpbuf(png_ptr), 1);
58 For writing a warning might have information about an error, so send
59 it to the error stack.
63 write_warn_handler(png_structp png_ptr, png_const_charp msg) {
64 mm_log((1, "PNG write warning '%s'\n", msg));
69 #define PNG_DIM_MAX 0x7fffffffL
72 i_writepng_wiol(i_img *im, io_glue *ig) {
74 png_infop info_ptr = NULL;
75 i_img_dim width,height,y;
76 volatile int cspace,channels;
78 int aspect_only, have_res;
80 unsigned char * volatile vdata = NULL;
82 mm_log((1,"i_writepng(im %p ,ig %p)\n", im, ig));
86 if (im->xsize > PNG_UINT_31_MAX || im->ysize > PNG_UINT_31_MAX) {
87 i_push_error(0, "image too large for PNG");
94 /* if we ever have 64-bit i_img_dim
95 * the libpng docs state that png_set_user_limits() can be used to
96 * override the PNG_USER_*_MAX limits, but as implemented they
97 * don't. We check against the theoretical limit of PNG here, and
98 * try to override the limits below, in case the libpng
99 * implementation ever matches the documentation.
101 * https://sourceforge.net/tracker/?func=detail&atid=105624&aid=3314943&group_id=5624
102 * fixed in libpng 1.5.3
104 if (width > PNG_DIM_MAX || height > PNG_DIM_MAX) {
105 i_push_error(0, "Image too large for PNG");
109 channels=im->channels;
111 if (channels > 2) { cspace = PNG_COLOR_TYPE_RGB; channels-=3; }
112 else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
114 if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
115 mm_log((1,"cspace=%d\n",cspace));
117 channels = im->channels;
119 /* Create and initialize the png_struct with the desired error handler
120 * functions. If you want to use the default stderr and longjump method,
121 * you can supply NULL for the last three parameters. We also check that
122 * the library version is compatible with the one used at compile time,
123 * in case we are using dynamically linked libraries. REQUIRED.
126 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
127 error_handler, write_warn_handler);
129 if (png_ptr == NULL) return 0;
132 /* Allocate/initialize the image information data. REQUIRED */
133 info_ptr = png_create_info_struct(png_ptr);
135 if (info_ptr == NULL) {
136 png_destroy_write_struct(&png_ptr, &info_ptr);
140 /* Set error handling. REQUIRED if you aren't supplying your own
141 * error hadnling functions in the png_create_write_struct() call.
143 if (setjmp(png_jmpbuf(png_ptr))) {
144 png_destroy_write_struct(&png_ptr, &info_ptr);
150 png_set_write_fn(png_ptr, (png_voidp) (ig), wiol_write_data, wiol_flush_data);
152 /* Set the image information here. Width and height are up to 2^31,
153 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
154 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
155 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
156 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
157 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
158 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
161 /* by default, libpng (not PNG) limits the image size to a maximum
162 * 1000000 pixels in each direction, but Imager doesn't.
163 * Configure libpng to avoid that limit.
165 png_set_user_limits(png_ptr, width, height);
167 png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
168 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
171 if (i_tags_get_float(&im->tags, "i_xres", 0, &xres)) {
172 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
173 ; /* nothing to do */
178 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
185 i_tags_get_int(&im->tags, "i_aspect_only", 0, &aspect_only);
188 png_set_pHYs(png_ptr, info_ptr, xres + 0.5, yres + 0.5,
189 aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER);
192 png_write_info(png_ptr, info_ptr);
194 vdata = data = mymalloc(im->xsize * im->channels);
195 for (y = 0; y < height; y++) {
196 i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
197 png_write_row(png_ptr, (png_bytep)data);
201 png_write_end(png_ptr, info_ptr);
203 png_destroy_write_struct(&png_ptr, &info_ptr);
212 get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth);
216 } i_png_read_state, *i_png_read_statep;
219 read_warn_handler(png_structp, png_const_charp);
222 cleanup_read_state(i_png_read_statep);
225 i_readpng_wiol(io_glue *ig) {
229 png_uint_32 width, height;
230 int bit_depth, color_type, interlace_type;
233 unsigned int sig_read;
235 i_img_dim wmax, hmax;
241 mm_log((1,"i_readpng_wiol(ig %p)\n", ig));
244 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &rs,
245 error_handler, read_warn_handler);
247 i_push_error(0, "Cannot create PNG read structure");
250 png_set_read_fn(png_ptr, (png_voidp) (ig), wiol_read_data);
252 info_ptr = png_create_info_struct(png_ptr);
253 if (info_ptr == NULL) {
254 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
255 i_push_error(0, "Cannot create PNG info structure");
259 if (setjmp(png_jmpbuf(png_ptr))) {
260 if (im) i_img_destroy(im);
261 mm_log((1,"i_readpng_wiol: error.\n"));
262 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
263 cleanup_read_state(&rs);
267 /* we do our own limit checks */
268 png_set_user_limits(png_ptr, PNG_DIM_MAX, PNG_DIM_MAX);
270 png_set_sig_bytes(png_ptr, sig_read);
271 png_read_info(png_ptr, info_ptr);
272 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
275 "png_get_IHDR results: width %d, height %d, bit_depth %d, color_type %d, interlace_type %d\n",
276 width,height,bit_depth,color_type,interlace_type));
278 CC2C[PNG_COLOR_TYPE_GRAY]=1;
279 CC2C[PNG_COLOR_TYPE_PALETTE]=3;
280 CC2C[PNG_COLOR_TYPE_RGB]=3;
281 CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
282 CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
283 channels = CC2C[color_type];
285 mm_log((1,"i_readpng_wiol: channels %d\n",channels));
287 if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
288 mm_log((1, "i_readpnm: image size exceeds limits\n"));
289 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
293 if (color_type == PNG_COLOR_TYPE_PALETTE) {
294 im = read_paletted(png_ptr, info_ptr, channels, width, height);
296 else if (color_type == PNG_COLOR_TYPE_GRAY
298 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
299 im = read_bilevel(png_ptr, info_ptr, width, height);
301 else if (bit_depth == 16) {
302 im = read_direct16(png_ptr, info_ptr, channels, width, height);
305 im = read_direct8(png_ptr, info_ptr, channels, width, height);
309 get_png_tags(im, png_ptr, info_ptr, bit_depth);
311 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
315 i_tags_set(&im->tags, "png_warnings", rs.warnings, -1);
318 cleanup_read_state(&rs);
320 mm_log((1,"(%p) <- i_readpng_wiol\n", im));
326 read_direct8(png_structp png_ptr, png_infop info_ptr, int channels,
327 i_img_dim width, i_img_dim height) {
328 i_img * volatile vim = NULL;
329 int color_type = png_get_color_type(png_ptr, info_ptr);
330 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
332 int number_passes, pass;
335 unsigned char * volatile vline = NULL;
337 if (setjmp(png_jmpbuf(png_ptr))) {
338 if (vim) i_img_destroy(vim);
339 if (vline) myfree(vline);
344 number_passes = png_set_interlace_handling(png_ptr);
345 mm_log((1,"number of passes=%d\n",number_passes));
347 png_set_strip_16(png_ptr);
348 png_set_packing(png_ptr);
350 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
351 png_set_expand(png_ptr);
353 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
355 mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels));
356 png_set_expand(png_ptr);
359 png_read_update_info(png_ptr, info_ptr);
361 im = vim = i_img_8_new(width,height,channels);
363 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
367 line = vline = mymalloc(channels * width);
368 for (pass = 0; pass < number_passes; pass++) {
369 for (y = 0; y < height; y++) {
371 i_gsamp(im, 0, width, y, line, NULL, channels);
372 png_read_row(png_ptr,(png_bytep)line, NULL);
373 i_psamp(im, 0, width, y, line, NULL, channels);
379 png_read_end(png_ptr, info_ptr);
385 read_direct16(png_structp png_ptr, png_infop info_ptr, int channels,
386 i_img_dim width, i_img_dim height) {
387 i_img * volatile vim = NULL;
388 int color_type = png_get_color_type(png_ptr, info_ptr);
390 int number_passes, pass;
393 unsigned char * volatile vline = NULL;
395 unsigned * volatile vbits_line = NULL;
398 if (setjmp(png_jmpbuf(png_ptr))) {
399 if (vim) i_img_destroy(vim);
400 if (vline) myfree(vline);
401 if (vbits_line) myfree(vbits_line);
406 number_passes = png_set_interlace_handling(png_ptr);
407 mm_log((1,"number of passes=%d\n",number_passes));
409 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
411 mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels));
412 png_set_expand(png_ptr);
415 png_read_update_info(png_ptr, info_ptr);
417 im = vim = i_img_16_new(width,height,channels);
419 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
423 row_bytes = png_get_rowbytes(png_ptr, info_ptr);
424 line = vline = mymalloc(row_bytes);
425 memset(line, 0, row_bytes);
426 bits_line = vbits_line = mymalloc(sizeof(unsigned) * width * channels);
427 for (pass = 0; pass < number_passes; pass++) {
428 for (y = 0; y < height; y++) {
430 i_gsamp_bits(im, 0, width, y, bits_line, NULL, channels, 16);
431 for (x = 0; x < width * channels; ++x) {
432 line[x*2] = bits_line[x] >> 8;
433 line[x*2+1] = bits_line[x] & 0xff;
436 png_read_row(png_ptr,(png_bytep)line, NULL);
437 for (x = 0; x < width * channels; ++x)
438 bits_line[x] = (line[x*2] << 8) + line[x*2+1];
439 i_psamp_bits(im, 0, width, y, bits_line, NULL, channels, 16);
447 png_read_end(png_ptr, info_ptr);
453 read_bilevel(png_structp png_ptr, png_infop info_ptr,
454 i_img_dim width, i_img_dim height) {
455 i_img * volatile vim = NULL;
457 int number_passes, pass;
460 unsigned char * volatile vline = NULL;
463 if (setjmp(png_jmpbuf(png_ptr))) {
464 if (vim) i_img_destroy(vim);
465 if (vline) myfree(vline);
470 number_passes = png_set_interlace_handling(png_ptr);
471 mm_log((1,"number of passes=%d\n",number_passes));
473 png_set_packing(png_ptr);
475 png_set_expand(png_ptr);
477 png_read_update_info(png_ptr, info_ptr);
479 im = vim = i_img_pal_new(width, height, 1, 256);
481 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
485 palette[0].channel[0] = palette[0].channel[1] = palette[0].channel[2] =
486 palette[0].channel[3] = 0;
487 palette[1].channel[0] = palette[1].channel[1] = palette[1].channel[2] =
488 palette[1].channel[3] = 255;
489 i_addcolors(im, palette, 2);
491 line = vline = mymalloc(width);
492 memset(line, 0, width);
493 for (pass = 0; pass < number_passes; pass++) {
494 for (y = 0; y < height; y++) {
496 i_gpal(im, 0, width, y, line);
497 /* expand indexes back to 0/255 */
498 for (x = 0; x < width; ++x)
499 line[x] = line[x] ? 255 : 0;
501 png_read_row(png_ptr,(png_bytep)line, NULL);
503 /* back to palette indexes */
504 for (x = 0; x < width; ++x)
505 line[x] = line[x] ? 1 : 0;
506 i_ppal(im, 0, width, y, line);
512 png_read_end(png_ptr, info_ptr);
517 /* FIXME: do we need to unscale palette color values from the
520 read_paletted(png_structp png_ptr, png_infop info_ptr, int channels,
521 i_img_dim width, i_img_dim height) {
522 i_img * volatile vim = NULL;
523 int color_type = png_get_color_type(png_ptr, info_ptr);
524 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
526 int number_passes, pass;
529 unsigned char * volatile vline = NULL;
531 png_colorp png_palette;
532 png_bytep png_pal_trans;
533 png_color_16p png_color_trans;
536 if (setjmp(png_jmpbuf(png_ptr))) {
537 if (vim) i_img_destroy(vim);
538 if (vline) myfree(vline);
543 number_passes = png_set_interlace_handling(png_ptr);
544 mm_log((1,"number of passes=%d\n",number_passes));
546 png_set_strip_16(png_ptr);
547 png_set_packing(png_ptr);
549 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
550 png_set_expand(png_ptr);
552 if (!png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette)) {
553 i_push_error(0, "Paletted image with no PLTE chunk");
557 if (png_get_tRNS(png_ptr, info_ptr, &png_pal_trans, &num_pal_trans,
565 png_read_update_info(png_ptr, info_ptr);
567 im = vim = i_img_pal_new(width, height, channels, 256);
569 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
573 for (i = 0; i < num_palette; ++i) {
576 c.rgba.r = png_palette[i].red;
577 c.rgba.g = png_palette[i].green;
578 c.rgba.b = png_palette[i].blue;
579 if (i < num_pal_trans)
580 c.rgba.a = png_pal_trans[i];
583 i_addcolors(im, &c, 1);
586 line = vline = mymalloc(width);
587 for (pass = 0; pass < number_passes; pass++) {
588 for (y = 0; y < height; y++) {
590 i_gpal(im, 0, width, y, line);
591 png_read_row(png_ptr,(png_bytep)line, NULL);
592 i_ppal(im, 0, width, y, line);
598 png_read_end(png_ptr, info_ptr);
604 get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth) {
605 png_uint_32 xres, yres;
608 i_tags_set(&im->tags, "i_format", "png", -1);
609 if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
610 mm_log((1,"pHYs (%d, %d) %d\n", xres, yres, unit_type));
611 if (unit_type == PNG_RESOLUTION_METER) {
612 i_tags_set_float2(&im->tags, "i_xres", 0, xres * 0.0254, 5);
613 i_tags_set_float2(&im->tags, "i_yres", 0, yres * 0.0254, 5);
616 i_tags_setn(&im->tags, "i_xres", xres);
617 i_tags_setn(&im->tags, "i_yres", yres);
618 i_tags_setn(&im->tags, "i_aspect_only", 1);
622 int interlace = png_get_interlace_type(png_ptr, info_ptr);
624 i_tags_setn(&im->tags, "png_interlace", interlace != PNG_INTERLACE_NONE);
626 case PNG_INTERLACE_NONE:
627 i_tags_set(&im->tags, "png_interlace_name", "none", -1);
630 case PNG_INTERLACE_ADAM7:
631 i_tags_set(&im->tags, "png_interlace_name", "adam7", -1);
635 i_tags_set(&im->tags, "png_interlace_name", "unknown", -1);
640 /* the various readers can call png_set_expand(), libpng will make
641 it's internal record of bit_depth at least 8 in that case */
642 i_tags_setn(&im->tags, "png_bits", bit_depth);
646 read_warn_handler(png_structp png_ptr, png_const_charp msg) {
647 i_png_read_statep rs = (i_png_read_statep)png_get_error_ptr(png_ptr);
651 mm_log((1, "PNG read warning '%s'\n", msg));
653 /* in case this is part of an error report */
654 i_push_error(0, msg);
656 /* and save in the warnings so if we do manage to succeed, we
657 * can save it as a tag
659 new_size = (rs->warnings ? strlen(rs->warnings) : 0)
661 + strlen(msg) /* new text */
663 workp = myrealloc(rs->warnings, new_size);
668 rs->warnings = workp;
672 cleanup_read_state(i_png_read_statep rs) {
674 myfree(rs->warnings);