PNG re-work: remove unused variables
[imager.git] / PNG / impng.c
CommitLineData
1d7e3124 1#include "impng.h"
02d1d628
AMH
2#include "png.h"
3
02d1d628
AMH
4/* this is a way to get number of channels from color space
5 * Color code to channel number */
6
b33c08f8 7static int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
02d1d628
AMH
8
9#define PNG_BYTES_TO_CHECK 4
cfb628e2
TC
10
11static i_img *
12read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
13
c631b2d5
TC
14static i_img *
15read_direct16(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
16
963d3602
TC
17static i_img *
18read_paletted(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
19
79b4c849
TC
20static i_img *
21read_bilevel(png_structp png_ptr, png_infop info_ptr, i_img_dim width, i_img_dim height);
22
647508aa
TC
23unsigned
24i_png_lib_version(void) {
25 return png_access_version_number();
26}
02d1d628 27
02d1d628 28static void
790923a4 29wiol_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
f5b4354e 30 io_glue *ig = png_get_io_ptr(png_ptr);
38eab175 31 ssize_t rc = i_io_read(ig, data, length);
790923a4 32 if (rc != length) png_error(png_ptr, "Read overflow error on an iolayer source.");
02d1d628
AMH
33}
34
02d1d628 35static void
790923a4 36wiol_write_data(png_structp png_ptr, png_bytep data, png_size_t length) {
38eab175 37 ssize_t rc;
f5b4354e 38 io_glue *ig = png_get_io_ptr(png_ptr);
6d5c85a2 39 rc = i_io_write(ig, data, length);
790923a4 40 if (rc != length) png_error(png_ptr, "Write error on an iolayer source.");
02d1d628
AMH
41}
42
43static void
790923a4
AMH
44wiol_flush_data(png_structp png_ptr) {
45 /* XXX : This needs to be added to the io layer */
02d1d628 46}
02d1d628 47
38eab175
TC
48static void
49error_handler(png_structp png_ptr, png_const_charp msg) {
50 mm_log((1, "PNG error: '%s'\n", msg));
51
52 i_push_error(0, msg);
53 longjmp(png_jmpbuf(png_ptr), 1);
54}
55
56/*
57
963d3602
TC
58 For writing a warning might have information about an error, so send
59 it to the error stack.
38eab175
TC
60
61*/
62static void
63write_warn_handler(png_structp png_ptr, png_const_charp msg) {
64 mm_log((1, "PNG write warning '%s'\n", msg));
65
66 i_push_error(0, msg);
67}
68
69#define PNG_DIM_MAX 0x7fffffffL
70
02d1d628 71undef_int
790923a4 72i_writepng_wiol(i_img *im, io_glue *ig) {
02d1d628 73 png_structp png_ptr;
a807aae6 74 png_infop info_ptr = NULL;
38eab175 75 i_img_dim width,height,y;
02d1d628 76 volatile int cspace,channels;
faa9b3e7
TC
77 double xres, yres;
78 int aspect_only, have_res;
34e56776
TC
79 unsigned char *data;
80 unsigned char * volatile vdata = NULL;
02d1d628 81
790923a4 82 mm_log((1,"i_writepng(im %p ,ig %p)\n", im, ig));
8d14daab
TC
83
84 i_clear_error();
85
86 if (im->xsize > PNG_UINT_31_MAX || im->ysize > PNG_UINT_31_MAX) {
87 i_push_error(0, "image too large for PNG");
88 return 0;
89 }
90
790923a4
AMH
91 height = im->ysize;
92 width = im->xsize;
02d1d628 93
38eab175
TC
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.
100 *
101 * https://sourceforge.net/tracker/?func=detail&atid=105624&aid=3314943&group_id=5624
647508aa 102 * fixed in libpng 1.5.3
34e56776 103 */
38eab175
TC
104 if (width > PNG_DIM_MAX || height > PNG_DIM_MAX) {
105 i_push_error(0, "Image too large for PNG");
106 return 0;
107 }
108
02d1d628
AMH
109 channels=im->channels;
110
790923a4 111 if (channels > 2) { cspace = PNG_COLOR_TYPE_RGB; channels-=3; }
02d1d628
AMH
112 else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
113
114 if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
115 mm_log((1,"cspace=%d\n",cspace));
116
790923a4 117 channels = im->channels;
02d1d628
AMH
118
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.
124 */
125
38eab175
TC
126 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
127 error_handler, write_warn_handler);
02d1d628 128
790923a4
AMH
129 if (png_ptr == NULL) return 0;
130
02d1d628
AMH
131
132 /* Allocate/initialize the image information data. REQUIRED */
133 info_ptr = png_create_info_struct(png_ptr);
134
135 if (info_ptr == NULL) {
a807aae6 136 png_destroy_write_struct(&png_ptr, &info_ptr);
790923a4 137 return 0;
02d1d628
AMH
138 }
139
140 /* Set error handling. REQUIRED if you aren't supplying your own
141 * error hadnling functions in the png_create_write_struct() call.
142 */
f5b4354e 143 if (setjmp(png_jmpbuf(png_ptr))) {
a807aae6 144 png_destroy_write_struct(&png_ptr, &info_ptr);
34e56776
TC
145 if (vdata)
146 myfree(vdata);
02d1d628
AMH
147 return(0);
148 }
149
790923a4 150 png_set_write_fn(png_ptr, (png_voidp) (ig), wiol_write_data, wiol_flush_data);
02d1d628
AMH
151
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
159 */
160
38eab175
TC
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.
164 */
165 png_set_user_limits(png_ptr, width, height);
166
02d1d628
AMH
167 png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
168 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
169
faa9b3e7
TC
170 have_res = 1;
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 */
174 else
175 yres = xres;
176 }
177 else {
178 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
179 xres = yres;
180 else
181 have_res = 0;
182 }
183 if (have_res) {
184 aspect_only = 0;
185 i_tags_get_int(&im->tags, "i_aspect_only", 0, &aspect_only);
186 xres /= 0.0254;
187 yres /= 0.0254;
188 png_set_pHYs(png_ptr, info_ptr, xres + 0.5, yres + 0.5,
189 aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER);
190 }
191
02d1d628 192 png_write_info(png_ptr, info_ptr);
790923a4 193
34e56776
TC
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);
faa9b3e7 198 }
34e56776 199 myfree(data);
790923a4 200
02d1d628 201 png_write_end(png_ptr, info_ptr);
790923a4 202
a807aae6 203 png_destroy_write_struct(&png_ptr, &info_ptr);
02d1d628 204
6d5c85a2
TC
205 if (i_io_close(ig))
206 return 0;
10461f9a 207
02d1d628
AMH
208 return(1);
209}
210
38eab175 211static void
79b4c849 212get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth);
38eab175
TC
213
214typedef struct {
215 char *warnings;
216} i_png_read_state, *i_png_read_statep;
02d1d628 217
38eab175
TC
218static void
219read_warn_handler(png_structp, png_const_charp);
02d1d628 220
38eab175
TC
221static void
222cleanup_read_state(i_png_read_statep);
02d1d628
AMH
223
224i_img*
1d7e3124 225i_readpng_wiol(io_glue *ig) {
02576e8d 226 i_img *im = NULL;
02d1d628
AMH
227 png_structp png_ptr;
228 png_infop info_ptr;
790923a4 229 png_uint_32 width, height;
02d1d628 230 int bit_depth, color_type, interlace_type;
432d0ff0 231 int channels;
02d1d628 232 unsigned int sig_read;
38eab175 233 i_png_read_state rs;
02d1d628 234
38eab175 235 rs.warnings = NULL;
790923a4 236 sig_read = 0;
02d1d628 237
1d7e3124 238 mm_log((1,"i_readpng_wiol(ig %p)\n", ig));
38eab175 239 i_clear_error();
02d1d628 240
38eab175
TC
241 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &rs,
242 error_handler, read_warn_handler);
243 if (!png_ptr) {
244 i_push_error(0, "Cannot create PNG read structure");
245 return NULL;
246 }
790923a4 247 png_set_read_fn(png_ptr, (png_voidp) (ig), wiol_read_data);
02d1d628
AMH
248
249 info_ptr = png_create_info_struct(png_ptr);
250 if (info_ptr == NULL) {
251 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
38eab175 252 i_push_error(0, "Cannot create PNG info structure");
02d1d628
AMH
253 return NULL;
254 }
255
f5b4354e 256 if (setjmp(png_jmpbuf(png_ptr))) {
02576e8d 257 if (im) i_img_destroy(im);
790923a4 258 mm_log((1,"i_readpng_wiol: error.\n"));
02d1d628 259 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
38eab175 260 cleanup_read_state(&rs);
02d1d628
AMH
261 return NULL;
262 }
647508aa
TC
263
264 /* we do our own limit checks */
265 png_set_user_limits(png_ptr, PNG_DIM_MAX, PNG_DIM_MAX);
790923a4 266
02d1d628
AMH
267 png_set_sig_bytes(png_ptr, sig_read);
268 png_read_info(png_ptr, info_ptr);
269 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
270
271 mm_log((1,
790923a4 272 "png_get_IHDR results: width %d, height %d, bit_depth %d, color_type %d, interlace_type %d\n",
02d1d628
AMH
273 width,height,bit_depth,color_type,interlace_type));
274
275 CC2C[PNG_COLOR_TYPE_GRAY]=1;
276 CC2C[PNG_COLOR_TYPE_PALETTE]=3;
277 CC2C[PNG_COLOR_TYPE_RGB]=3;
278 CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
279 CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
790923a4
AMH
280 channels = CC2C[color_type];
281
282 mm_log((1,"i_readpng_wiol: channels %d\n",channels));
283
77157728
TC
284 if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
285 mm_log((1, "i_readpnm: image size exceeds limits\n"));
286 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
287 return NULL;
288 }
289
963d3602
TC
290 if (color_type == PNG_COLOR_TYPE_PALETTE) {
291 im = read_paletted(png_ptr, info_ptr, channels, width, height);
292 }
79b4c849
TC
293 else if (color_type == PNG_COLOR_TYPE_GRAY
294 && bit_depth == 1
295 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
296 im = read_bilevel(png_ptr, info_ptr, width, height);
297 }
c631b2d5
TC
298 else if (bit_depth == 16) {
299 im = read_direct16(png_ptr, info_ptr, channels, width, height);
300 }
963d3602
TC
301 else {
302 im = read_direct8(png_ptr, info_ptr, channels, width, height);
303 }
cfb628e2
TC
304
305 if (im)
79b4c849 306 get_png_tags(im, png_ptr, info_ptr, bit_depth);
cfb628e2
TC
307
308 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
309
310 if (im) {
311 if (rs.warnings) {
312 i_tags_set(&im->tags, "png_warnings", rs.warnings, -1);
313 }
314 }
315 cleanup_read_state(&rs);
316
317 mm_log((1,"(%p) <- i_readpng_wiol\n", im));
318
319 return im;
320}
321
322static i_img *
323read_direct8(png_structp png_ptr, png_infop info_ptr, int channels,
324 i_img_dim width, i_img_dim height) {
325 i_img * volatile vim = NULL;
326 int color_type = png_get_color_type(png_ptr, info_ptr);
327 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
328 i_img_dim y;
329 int number_passes, pass;
330 i_img *im;
34e56776
TC
331 unsigned char *line;
332 unsigned char * volatile vline = NULL;
cfb628e2
TC
333
334 if (setjmp(png_jmpbuf(png_ptr))) {
335 if (vim) i_img_destroy(vim);
34e56776 336 if (vline) myfree(vline);
cfb628e2
TC
337
338 return NULL;
339 }
340
341 number_passes = png_set_interlace_handling(png_ptr);
342 mm_log((1,"number of passes=%d\n",number_passes));
343
02d1d628
AMH
344 png_set_strip_16(png_ptr);
345 png_set_packing(png_ptr);
6829f5f6 346
cfb628e2
TC
347 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
348 png_set_expand(png_ptr);
349
6829f5f6
AMH
350 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
351 channels++;
352 mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels));
353 png_set_expand(png_ptr);
354 }
790923a4 355
02d1d628 356 png_read_update_info(png_ptr, info_ptr);
790923a4 357
cfb628e2 358 im = vim = i_img_8_new(width,height,channels);
352c64ed
TC
359 if (!im) {
360 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
361 return NULL;
362 }
02d1d628 363
34e56776 364 line = vline = mymalloc(channels * width);
cfb628e2
TC
365 for (pass = 0; pass < number_passes; pass++) {
366 for (y = 0; y < height; y++) {
34e56776
TC
367 if (pass > 0)
368 i_gsamp(im, 0, width, y, line, NULL, channels);
369 png_read_row(png_ptr,(png_bytep)line, NULL);
370 i_psamp(im, 0, width, y, line, NULL, channels);
cfb628e2 371 }
38eab175 372 }
34e56776
TC
373 myfree(line);
374 vline = NULL;
02d1d628 375
cfb628e2
TC
376 png_read_end(png_ptr, info_ptr);
377
790923a4
AMH
378 return im;
379}
faa9b3e7 380
c631b2d5
TC
381static i_img *
382read_direct16(png_structp png_ptr, png_infop info_ptr, int channels,
383 i_img_dim width, i_img_dim height) {
384 i_img * volatile vim = NULL;
c631b2d5
TC
385 i_img_dim x, y;
386 int number_passes, pass;
387 i_img *im;
388 unsigned char *line;
389 unsigned char * volatile vline = NULL;
390 unsigned *bits_line;
391 unsigned * volatile vbits_line = NULL;
392 size_t row_bytes;
393
394 if (setjmp(png_jmpbuf(png_ptr))) {
395 if (vim) i_img_destroy(vim);
396 if (vline) myfree(vline);
397 if (vbits_line) myfree(vbits_line);
398
399 return NULL;
400 }
401
402 number_passes = png_set_interlace_handling(png_ptr);
403 mm_log((1,"number of passes=%d\n",number_passes));
404
405 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
406 channels++;
407 mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels));
408 png_set_expand(png_ptr);
409 }
410
411 png_read_update_info(png_ptr, info_ptr);
412
413 im = vim = i_img_16_new(width,height,channels);
414 if (!im) {
415 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
416 return NULL;
417 }
418
419 row_bytes = png_get_rowbytes(png_ptr, info_ptr);
420 line = vline = mymalloc(row_bytes);
421 memset(line, 0, row_bytes);
422 bits_line = vbits_line = mymalloc(sizeof(unsigned) * width * channels);
423 for (pass = 0; pass < number_passes; pass++) {
424 for (y = 0; y < height; y++) {
425 if (pass > 0) {
426 i_gsamp_bits(im, 0, width, y, bits_line, NULL, channels, 16);
427 for (x = 0; x < width * channels; ++x) {
428 line[x*2] = bits_line[x] >> 8;
429 line[x*2+1] = bits_line[x] & 0xff;
430 }
431 }
432 png_read_row(png_ptr,(png_bytep)line, NULL);
433 for (x = 0; x < width * channels; ++x)
434 bits_line[x] = (line[x*2] << 8) + line[x*2+1];
435 i_psamp_bits(im, 0, width, y, bits_line, NULL, channels, 16);
436 }
437 }
438 myfree(line);
439 myfree(bits_line);
440 vline = NULL;
441 vbits_line = NULL;
442
443 png_read_end(png_ptr, info_ptr);
444
445 return im;
446}
447
79b4c849
TC
448static i_img *
449read_bilevel(png_structp png_ptr, png_infop info_ptr,
450 i_img_dim width, i_img_dim height) {
451 i_img * volatile vim = NULL;
452 i_img_dim x, y;
453 int number_passes, pass;
454 i_img *im;
455 unsigned char *line;
456 unsigned char * volatile vline = NULL;
457 i_color palette[2];
458
459 if (setjmp(png_jmpbuf(png_ptr))) {
460 if (vim) i_img_destroy(vim);
461 if (vline) myfree(vline);
462
463 return NULL;
464 }
465
466 number_passes = png_set_interlace_handling(png_ptr);
467 mm_log((1,"number of passes=%d\n",number_passes));
468
469 png_set_packing(png_ptr);
470
471 png_set_expand(png_ptr);
472
473 png_read_update_info(png_ptr, info_ptr);
474
475 im = vim = i_img_pal_new(width, height, 1, 256);
476 if (!im) {
477 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
478 return NULL;
479 }
480
481 palette[0].channel[0] = palette[0].channel[1] = palette[0].channel[2] =
482 palette[0].channel[3] = 0;
483 palette[1].channel[0] = palette[1].channel[1] = palette[1].channel[2] =
484 palette[1].channel[3] = 255;
485 i_addcolors(im, palette, 2);
486
487 line = vline = mymalloc(width);
488 memset(line, 0, width);
489 for (pass = 0; pass < number_passes; pass++) {
490 for (y = 0; y < height; y++) {
491 if (pass > 0) {
492 i_gpal(im, 0, width, y, line);
493 /* expand indexes back to 0/255 */
494 for (x = 0; x < width; ++x)
495 line[x] = line[x] ? 255 : 0;
496 }
497 png_read_row(png_ptr,(png_bytep)line, NULL);
498
499 /* back to palette indexes */
500 for (x = 0; x < width; ++x)
501 line[x] = line[x] ? 1 : 0;
502 i_ppal(im, 0, width, y, line);
503 }
504 }
505 myfree(line);
506 vline = NULL;
507
508 png_read_end(png_ptr, info_ptr);
509
510 return im;
511}
512
513/* FIXME: do we need to unscale palette color values from the
514 supplied alphas? */
963d3602
TC
515static i_img *
516read_paletted(png_structp png_ptr, png_infop info_ptr, int channels,
517 i_img_dim width, i_img_dim height) {
518 i_img * volatile vim = NULL;
519 int color_type = png_get_color_type(png_ptr, info_ptr);
520 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
521 i_img_dim y;
522 int number_passes, pass;
523 i_img *im;
524 unsigned char *line;
525 unsigned char * volatile vline = NULL;
526 int num_palette, i;
527 png_colorp png_palette;
528 png_bytep png_pal_trans;
529 png_color_16p png_color_trans;
530 int num_pal_trans;
531
532 if (setjmp(png_jmpbuf(png_ptr))) {
533 if (vim) i_img_destroy(vim);
534 if (vline) myfree(vline);
535
536 return NULL;
537 }
538
539 number_passes = png_set_interlace_handling(png_ptr);
540 mm_log((1,"number of passes=%d\n",number_passes));
541
542 png_set_strip_16(png_ptr);
543 png_set_packing(png_ptr);
544
545 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
546 png_set_expand(png_ptr);
547
548 if (!png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette)) {
549 i_push_error(0, "Paletted image with no PLTE chunk");
550 return NULL;
551 }
552
553 if (png_get_tRNS(png_ptr, info_ptr, &png_pal_trans, &num_pal_trans,
554 &png_color_trans)) {
555 channels++;
556 }
557 else {
558 num_pal_trans = 0;
559 }
560
561 png_read_update_info(png_ptr, info_ptr);
562
563 im = vim = i_img_pal_new(width, height, channels, 256);
564 if (!im) {
565 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
566 return NULL;
567 }
568
569 for (i = 0; i < num_palette; ++i) {
570 i_color c;
571
572 c.rgba.r = png_palette[i].red;
573 c.rgba.g = png_palette[i].green;
574 c.rgba.b = png_palette[i].blue;
575 if (i < num_pal_trans)
576 c.rgba.a = png_pal_trans[i];
577 else
578 c.rgba.a = 255;
579 i_addcolors(im, &c, 1);
580 }
581
582 line = vline = mymalloc(width);
583 for (pass = 0; pass < number_passes; pass++) {
584 for (y = 0; y < height; y++) {
585 if (pass > 0)
586 i_gpal(im, 0, width, y, line);
587 png_read_row(png_ptr,(png_bytep)line, NULL);
588 i_ppal(im, 0, width, y, line);
589 }
590 }
591 myfree(line);
592 vline = NULL;
593
594 png_read_end(png_ptr, info_ptr);
595
596 return im;
597}
598
38eab175 599static void
79b4c849 600get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth) {
faa9b3e7
TC
601 png_uint_32 xres, yres;
602 int unit_type;
352c64ed 603
1d7e3124 604 i_tags_set(&im->tags, "i_format", "png", -1);
faa9b3e7
TC
605 if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
606 mm_log((1,"pHYs (%d, %d) %d\n", xres, yres, unit_type));
607 if (unit_type == PNG_RESOLUTION_METER) {
2e41e30b
TC
608 i_tags_set_float2(&im->tags, "i_xres", 0, xres * 0.0254, 5);
609 i_tags_set_float2(&im->tags, "i_yres", 0, yres * 0.0254, 5);
faa9b3e7
TC
610 }
611 else {
1d7e3124
TC
612 i_tags_setn(&im->tags, "i_xres", xres);
613 i_tags_setn(&im->tags, "i_yres", yres);
614 i_tags_setn(&im->tags, "i_aspect_only", 1);
faa9b3e7
TC
615 }
616 }
a4fa5d5e
TC
617 {
618 int interlace = png_get_interlace_type(png_ptr, info_ptr);
619
620 i_tags_setn(&im->tags, "png_interlace", interlace != PNG_INTERLACE_NONE);
621 switch (interlace) {
622 case PNG_INTERLACE_NONE:
623 i_tags_set(&im->tags, "png_interlace_name", "none", -1);
624 break;
625
626 case PNG_INTERLACE_ADAM7:
627 i_tags_set(&im->tags, "png_interlace_name", "adam7", -1);
628 break;
629
630 default:
631 i_tags_set(&im->tags, "png_interlace_name", "unknown", -1);
632 break;
633 }
00cff942
TC
634 }
635
79b4c849
TC
636 /* the various readers can call png_set_expand(), libpng will make
637 it's internal record of bit_depth at least 8 in that case */
638 i_tags_setn(&im->tags, "png_bits", bit_depth);
faa9b3e7 639}
38eab175
TC
640
641static void
642read_warn_handler(png_structp png_ptr, png_const_charp msg) {
643 i_png_read_statep rs = (i_png_read_statep)png_get_error_ptr(png_ptr);
644 char *workp;
645 size_t new_size;
646
647 mm_log((1, "PNG read warning '%s'\n", msg));
648
649 /* in case this is part of an error report */
650 i_push_error(0, msg);
651
652 /* and save in the warnings so if we do manage to succeed, we
653 * can save it as a tag
654 */
655 new_size = (rs->warnings ? strlen(rs->warnings) : 0)
656 + 1 /* NUL */
657 + strlen(msg) /* new text */
658 + 1; /* newline */
659 workp = myrealloc(rs->warnings, new_size);
660 if (!rs->warnings)
661 *workp = '\0';
662 strcat(workp, msg);
663 strcat(workp, "\n");
664 rs->warnings = workp;
665}
666
667static void
668cleanup_read_state(i_png_read_statep rs) {
669 if (rs->warnings)
670 myfree(rs->warnings);
671}