1#include "mupdf/fitz.h"
2
3#include <zlib.h>
4
5#include <limits.h>
6#include <string.h>
7
8struct info
9{
10 unsigned int width, height, depth, n;
11 enum fz_colorspace_type type;
12 int interlace, indexed;
13 unsigned int size;
14 unsigned char *samples;
15 unsigned char palette[256*4];
16 int transparency;
17 int trns[3];
18 int xres, yres;
19 fz_colorspace *cs;
20};
21
22static inline unsigned int getuint(const unsigned char *p)
23{
24 return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
25}
26
27static inline int getcomp(const unsigned char *line, int x, int bpc)
28{
29 switch (bpc)
30 {
31 case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1;
32 case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3;
33 case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15;
34 case 8: return line[x];
35 case 16: return line[x << 1] << 8 | line[(x << 1) + 1];
36 }
37 return 0;
38}
39
40static inline void putcomp(unsigned char *line, int x, int bpc, int value)
41{
42 int maxval = (1 << bpc) - 1;
43
44 switch (bpc)
45 {
46 case 1: line[x >> 3] &= ~(maxval << (7 - (x & 7))); break;
47 case 2: line[x >> 2] &= ~(maxval << ((3 - (x & 3)) << 1)); break;
48 case 4: line[x >> 1] &= ~(maxval << ((1 - (x & 1)) << 2)); break;
49 }
50
51 switch (bpc)
52 {
53 case 1: line[x >> 3] |= value << (7 - (x & 7)); break;
54 case 2: line[x >> 2] |= value << ((3 - (x & 3)) << 1); break;
55 case 4: line[x >> 1] |= value << ((1 - (x & 1)) << 2); break;
56 case 8: line[x] = value; break;
57 case 16: line[x << 1] = value >> 8; line[(x << 1) + 1] = value & 0xFF; break;
58 }
59}
60
61static const unsigned char png_signature[8] =
62{
63 137, 80, 78, 71, 13, 10, 26, 10
64};
65
66static inline int paeth(int a, int b, int c)
67{
68 /* The definitions of ac and bc are correct, not a typo. */
69 int ac = b - c, bc = a - c, abcc = ac + bc;
70 int pa = (ac < 0 ? -ac : ac);
71 int pb = (bc < 0 ? -bc : bc);
72 int pc = (abcc < 0 ? -abcc : abcc);
73 return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
74}
75
76static void
77png_predict(unsigned char *samples, unsigned int width, unsigned int height, unsigned int n, unsigned int depth)
78{
79 unsigned int stride = (width * n * depth + 7) / 8;
80 unsigned int bpp = (n * depth + 7) / 8;
81 unsigned int i, row;
82
83 for (row = 0; row < height; row ++)
84 {
85 unsigned char *src = samples + (unsigned int)((stride + 1) * row);
86 unsigned char *dst = samples + (unsigned int)(stride * row);
87
88 unsigned char *a = dst;
89 unsigned char *b = dst - stride;
90 unsigned char *c = dst - stride;
91
92 switch (*src++)
93 {
94 default:
95 case 0: /* None */
96 for (i = 0; i < stride; i++)
97 *dst++ = *src++;
98 break;
99
100 case 1: /* Sub */
101 for (i = 0; i < bpp; i++)
102 *dst++ = *src++;
103 for (i = bpp; i < stride; i++)
104 *dst++ = *src++ + *a++;
105 break;
106
107 case 2: /* Up */
108 if (row == 0)
109 for (i = 0; i < stride; i++)
110 *dst++ = *src++;
111 else
112 for (i = 0; i < stride; i++)
113 *dst++ = *src++ + *b++;
114 break;
115
116 case 3: /* Average */
117 if (row == 0)
118 {
119 for (i = 0; i < bpp; i++)
120 *dst++ = *src++;
121 for (i = bpp; i < stride; i++)
122 *dst++ = *src++ + (*a++ >> 1);
123 }
124 else
125 {
126 for (i = 0; i < bpp; i++)
127 *dst++ = *src++ + (*b++ >> 1);
128 for (i = bpp; i < stride; i++)
129 *dst++ = *src++ + ((*b++ + *a++) >> 1);
130 }
131 break;
132
133 case 4: /* Paeth */
134 if (row == 0)
135 {
136 for (i = 0; i < bpp; i++)
137 *dst++ = *src++ + paeth(0, 0, 0);
138 for (i = bpp; i < stride; i++)
139 *dst++ = *src++ + paeth(*a++, 0, 0);
140 }
141 else
142 {
143 for (i = 0; i < bpp; i++)
144 *dst++ = *src++ + paeth(0, *b++, 0);
145 for (i = bpp; i < stride; i++)
146 *dst++ = *src++ + paeth(*a++, *b++, *c++);
147 }
148 break;
149 }
150 }
151}
152
153static const unsigned int adam7_ix[7] = { 0, 4, 0, 2, 0, 1, 0 };
154static const unsigned int adam7_dx[7] = { 8, 8, 4, 4, 2, 2, 1 };
155static const unsigned int adam7_iy[7] = { 0, 0, 4, 0, 2, 0, 1 };
156static const unsigned int adam7_dy[7] = { 8, 8, 8, 4, 4, 2, 2 };
157
158static void
159png_deinterlace_passes(fz_context *ctx, struct info *info, unsigned int *w, unsigned int *h, unsigned int *ofs)
160{
161 int p, bpp = info->depth * info->n;
162 ofs[0] = 0;
163 for (p = 0; p < 7; p++)
164 {
165 w[p] = (info->width + adam7_dx[p] - adam7_ix[p] - 1) / adam7_dx[p];
166 h[p] = (info->height + adam7_dy[p] - adam7_iy[p] - 1) / adam7_dy[p];
167 if (w[p] == 0) h[p] = 0;
168 if (h[p] == 0) w[p] = 0;
169 if (w[p] && h[p])
170 ofs[p + 1] = ofs[p] + h[p] * (1 + (w[p] * bpp + 7) / 8);
171 else
172 ofs[p + 1] = ofs[p];
173 }
174}
175
176static void
177png_deinterlace(fz_context *ctx, struct info *info, unsigned int *passw, unsigned int *passh, unsigned int *passofs)
178{
179 unsigned int n = info->n;
180 unsigned int depth = info->depth;
181 unsigned int stride = (info->width * n * depth + 7) / 8;
182 unsigned char *output;
183 unsigned int p, x, y, k;
184
185 if (info->height > UINT_MAX / stride)
186 fz_throw(ctx, FZ_ERROR_MEMORY, "image too large");
187 output = fz_malloc(ctx, info->height * stride);
188
189 for (p = 0; p < 7; p++)
190 {
191 unsigned char *sp = info->samples + (passofs[p]);
192 unsigned int w = passw[p];
193 unsigned int h = passh[p];
194
195 png_predict(sp, w, h, n, depth);
196 for (y = 0; y < h; y++)
197 {
198 for (x = 0; x < w; x++)
199 {
200 int outx = x * adam7_dx[p] + adam7_ix[p];
201 int outy = y * adam7_dy[p] + adam7_iy[p];
202 unsigned char *dp = output + outy * stride;
203 for (k = 0; k < n; k++)
204 {
205 int v = getcomp(sp, x * n + k, depth);
206 putcomp(dp, outx * n + k, depth, v);
207 }
208 }
209 sp += (w * depth * n + 7) / 8;
210 }
211 }
212
213 fz_free(ctx, info->samples);
214 info->samples = output;
215}
216
217static void
218png_read_ihdr(fz_context *ctx, struct info *info, const unsigned char *p, unsigned int size)
219{
220 int color, compression, filter;
221
222 if (size != 13)
223 fz_throw(ctx, FZ_ERROR_GENERIC, "IHDR chunk is the wrong size");
224
225 info->width = getuint(p + 0);
226 info->height = getuint(p + 4);
227 info->depth = p[8];
228
229 color = p[9];
230 compression = p[10];
231 filter = p[11];
232 info->interlace = p[12];
233
234 if (info->width <= 0)
235 fz_throw(ctx, FZ_ERROR_GENERIC, "image width must be > 0");
236 if (info->height <= 0)
237 fz_throw(ctx, FZ_ERROR_GENERIC, "image height must be > 0");
238
239 if (info->depth != 1 && info->depth != 2 && info->depth != 4 &&
240 info->depth != 8 && info->depth != 16)
241 fz_throw(ctx, FZ_ERROR_GENERIC, "image bit depth must be one of 1, 2, 4, 8, 16");
242 if (color == 2 && info->depth < 8)
243 fz_throw(ctx, FZ_ERROR_GENERIC, "illegal bit depth for truecolor");
244 if (color == 3 && info->depth > 8)
245 fz_throw(ctx, FZ_ERROR_GENERIC, "illegal bit depth for indexed");
246 if (color == 4 && info->depth < 8)
247 fz_throw(ctx, FZ_ERROR_GENERIC, "illegal bit depth for grayscale with alpha");
248 if (color == 6 && info->depth < 8)
249 fz_throw(ctx, FZ_ERROR_GENERIC, "illegal bit depth for truecolor with alpha");
250
251 info->indexed = 0;
252 if (color == 0) /* gray */
253 info->n = 1, info->type = FZ_COLORSPACE_GRAY;
254 else if (color == 2) /* rgb */
255 info->n = 3, info->type = FZ_COLORSPACE_RGB;
256 else if (color == 4) /* gray alpha */
257 info->n = 2, info->type = FZ_COLORSPACE_GRAY;
258 else if (color == 6) /* rgb alpha */
259 info->n = 4, info->type = FZ_COLORSPACE_RGB;
260 else if (color == 3) /* indexed */
261 {
262 info->type = FZ_COLORSPACE_RGB; /* after colorspace expansion it will be */
263 info->indexed = 1;
264 info->n = 1;
265 }
266 else
267 fz_throw(ctx, FZ_ERROR_GENERIC, "unknown color type");
268
269 if (compression != 0)
270 fz_throw(ctx, FZ_ERROR_GENERIC, "unknown compression method");
271 if (filter != 0)
272 fz_throw(ctx, FZ_ERROR_GENERIC, "unknown filter method");
273 if (info->interlace != 0 && info->interlace != 1)
274 fz_throw(ctx, FZ_ERROR_GENERIC, "interlace method not supported");
275 if (info->height > UINT_MAX / info->width / info->n / (info->depth / 8 + 1))
276 fz_throw(ctx, FZ_ERROR_GENERIC, "image dimensions might overflow");
277}
278
279static void
280png_read_plte(fz_context *ctx, struct info *info, const unsigned char *p, unsigned int size)
281{
282 int n = size / 3;
283 int i;
284
285 if (n > 256)
286 {
287 fz_warn(ctx, "too many samples in palette");
288 n = 256;
289 }
290
291 for (i = 0; i < n; i++)
292 {
293 info->palette[i * 4] = p[i * 3];
294 info->palette[i * 4 + 1] = p[i * 3 + 1];
295 info->palette[i * 4 + 2] = p[i * 3 + 2];
296 }
297
298 /* Fill in any missing palette entries */
299 for (; i < 256; i++)
300 {
301 info->palette[i * 4] = 0;
302 info->palette[i * 4 + 1] = 0;
303 info->palette[i * 4 + 2] = 0;
304 }
305}
306
307static void
308png_read_trns(fz_context *ctx, struct info *info, const unsigned char *p, unsigned int size)
309{
310 unsigned int i;
311
312 info->transparency = 1;
313
314 if (info->indexed)
315 {
316 if (size > 256)
317 {
318 fz_warn(ctx, "too many samples in transparency table");
319 size = 256;
320 }
321 for (i = 0; i < size; i++)
322 info->palette[i * 4 + 3] = p[i];
323 /* Fill in any missing entries */
324 for (; i < 256; i++)
325 info->palette[i * 4 + 3] = 255;
326 }
327 else
328 {
329 if (size != info->n * 2)
330 fz_throw(ctx, FZ_ERROR_GENERIC, "tRNS chunk is the wrong size");
331 for (i = 0; i < info->n; i++)
332 info->trns[i] = (p[i * 2] << 8 | p[i * 2 + 1]) & ((1 << info->depth) - 1);
333 }
334}
335
336static void
337png_read_icc(fz_context *ctx, struct info *info, const unsigned char *p, unsigned int size)
338{
339#if FZ_ENABLE_ICC
340 fz_stream *mstm = NULL, *zstm = NULL;
341 fz_colorspace *cs = NULL;
342 fz_buffer *buf = NULL;
343 size_t m = fz_mini(80, size);
344 size_t n = fz_strnlen((const char *)p, m);
345 if (n + 2 > m)
346 {
347 fz_warn(ctx, "invalid ICC profile name");
348 return;
349 }
350
351 fz_var(mstm);
352 fz_var(zstm);
353 fz_var(buf);
354
355 fz_try(ctx)
356 {
357 mstm = fz_open_memory(ctx, p + n + 2, size - n - 2);
358 zstm = fz_open_flated(ctx, mstm, 15);
359 buf = fz_read_all(ctx, zstm, 0);
360 cs = fz_new_icc_colorspace(ctx, info->type, 0, NULL, buf);
361 fz_drop_colorspace(ctx, info->cs);
362 info->cs = cs;
363 }
364 fz_always(ctx)
365 {
366 fz_drop_buffer(ctx, buf);
367 fz_drop_stream(ctx, zstm);
368 fz_drop_stream(ctx, mstm);
369 }
370 fz_catch(ctx)
371 fz_warn(ctx, "ignoring embedded ICC profile in PNG");
372#endif
373}
374
375static void
376png_read_idat(fz_context *ctx, struct info *info, const unsigned char *p, unsigned int size, z_stream *stm)
377{
378 int code;
379
380 stm->next_in = (Bytef*)p;
381 stm->avail_in = size;
382
383 code = inflate(stm, Z_SYNC_FLUSH);
384 if (code != Z_OK && code != Z_STREAM_END)
385 fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: %s", stm->msg);
386 if (stm->avail_in != 0)
387 {
388 if (stm->avail_out == 0)
389 fz_throw(ctx, FZ_ERROR_GENERIC, "ran out of output before input");
390 fz_throw(ctx, FZ_ERROR_GENERIC, "inflate did not consume buffer (%d remaining)", stm->avail_in);
391 }
392}
393
394static void
395png_read_phys(fz_context *ctx, struct info *info, const unsigned char *p, unsigned int size)
396{
397 if (size != 9)
398 fz_throw(ctx, FZ_ERROR_GENERIC, "pHYs chunk is the wrong size");
399 if (p[8] == 1)
400 {
401 info->xres = (getuint(p) * 254 + 5000) / 10000;
402 info->yres = (getuint(p + 4) * 254 + 5000) / 10000;
403 }
404}
405
406static void
407png_read_image(fz_context *ctx, struct info *info, const unsigned char *p, size_t total, int only_metadata)
408{
409 unsigned int passw[7], passh[7], passofs[8];
410 unsigned int code, size;
411 z_stream stm;
412
413 memset(info, 0, sizeof (struct info));
414 memset(info->palette, 255, sizeof(info->palette));
415 info->xres = 96;
416 info->yres = 96;
417
418 /* Read signature */
419
420 if (total < 8 + 12 || memcmp(p, png_signature, 8))
421 fz_throw(ctx, FZ_ERROR_GENERIC, "not a png image (wrong signature)");
422
423 p += 8;
424 total -= 8;
425
426 /* Read IHDR chunk (must come first) */
427
428 size = getuint(p);
429 if (total < 12 || size > total - 12)
430 fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in png image");
431
432 if (!memcmp(p + 4, "IHDR", 4))
433 png_read_ihdr(ctx, info, p + 8, size);
434 else
435 fz_throw(ctx, FZ_ERROR_GENERIC, "png file must start with IHDR chunk");
436
437 p += size + 12;
438 total -= size + 12;
439
440 /* Prepare output buffer */
441 if (!only_metadata)
442 {
443 if (!info->interlace)
444 {
445 info->size = info->height * (1 + (info->width * info->n * info->depth + 7) / 8);
446 }
447 else
448 {
449 png_deinterlace_passes(ctx, info, passw, passh, passofs);
450 info->size = passofs[7];
451 }
452
453 info->samples = fz_malloc(ctx, info->size);
454
455 stm.zalloc = fz_zlib_alloc;
456 stm.zfree = fz_zlib_free;
457 stm.opaque = ctx;
458
459 stm.next_out = info->samples;
460 stm.avail_out = info->size;
461
462 code = inflateInit(&stm);
463 if (code != Z_OK)
464 fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: %s", stm.msg);
465 }
466
467 fz_try(ctx)
468 {
469 /* Read remaining chunks until IEND */
470 while (total > 8)
471 {
472 size = getuint(p);
473
474 if (total < 12 || size > total - 12)
475 fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of data in png image");
476
477 if (!memcmp(p + 4, "PLTE", 4) && !only_metadata)
478 png_read_plte(ctx, info, p + 8, size);
479 if (!memcmp(p + 4, "tRNS", 4) && !only_metadata)
480 png_read_trns(ctx, info, p + 8, size);
481 if (!memcmp(p + 4, "pHYs", 4))
482 png_read_phys(ctx, info, p + 8, size);
483 if (!memcmp(p + 4, "IDAT", 4) && !only_metadata)
484 png_read_idat(ctx, info, p + 8, size, &stm);
485 if (!memcmp(p + 4, "iCCP", 4))
486 png_read_icc(ctx, info, p + 8, size);
487 if (!memcmp(p + 4, "IEND", 4))
488 break;
489
490 p += size + 12;
491 total -= size + 12;
492 }
493 if (!only_metadata && stm.avail_out != 0)
494 {
495 memset(stm.next_out, 0xff, stm.avail_out);
496 fz_warn(ctx, "missing pixel data in png image; possibly truncated");
497 }
498 else if (total <= 8)
499 fz_warn(ctx, "missing IEND chunk in png image; possibly truncated");
500 }
501 fz_catch(ctx)
502 {
503 if (!only_metadata)
504 {
505 inflateEnd(&stm);
506 fz_free(ctx, info->samples);
507 info->samples = NULL;
508 }
509 fz_rethrow(ctx);
510 }
511
512 if (!only_metadata)
513 {
514 code = inflateEnd(&stm);
515 if (code != Z_OK)
516 {
517 fz_free(ctx, info->samples);
518 info->samples = NULL;
519 fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: %s", stm.msg);
520 }
521
522 /* Apply prediction filter and deinterlacing */
523 fz_try(ctx)
524 {
525 if (!info->interlace)
526 png_predict(info->samples, info->width, info->height, info->n, info->depth);
527 else
528 png_deinterlace(ctx, info, passw, passh, passofs);
529 }
530 fz_catch(ctx)
531 {
532 fz_free(ctx, info->samples);
533 info->samples = NULL;
534 fz_rethrow(ctx);
535 }
536 }
537
538 if (info->cs && fz_colorspace_type(ctx, info->cs) != info->type)
539 {
540 fz_warn(ctx, "embedded ICC profile does not match PNG colorspace");
541 fz_drop_colorspace(ctx, info->cs);
542 info->cs = NULL;
543 }
544
545 if (info->cs == NULL)
546 {
547 if (info->n == 3 || info->n == 4 || info->indexed)
548 info->cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
549 else
550 info->cs = fz_keep_colorspace(ctx, fz_device_gray(ctx));
551 }
552}
553
554static fz_pixmap *
555png_expand_palette(fz_context *ctx, struct info *info, fz_pixmap *src)
556{
557 fz_pixmap *dst = fz_new_pixmap(ctx, info->cs, src->w, src->h, NULL, info->transparency);
558 unsigned char *sp = src->samples;
559 unsigned char *dp = dst->samples;
560 unsigned int x, y;
561 int dstride = dst->stride - dst->w * dst->n;
562 int sstride = src->stride - src->w * src->n;
563
564 dst->xres = src->xres;
565 dst->yres = src->yres;
566
567 for (y = info->height; y > 0; y--)
568 {
569 for (x = info->width; x > 0; x--)
570 {
571 int v = *sp << 2;
572 *dp++ = info->palette[v];
573 *dp++ = info->palette[v + 1];
574 *dp++ = info->palette[v + 2];
575 if (info->transparency)
576 *dp++ = info->palette[v + 3];
577 ++sp;
578 }
579 sp += sstride;
580 dp += dstride;
581 }
582
583 fz_drop_pixmap(ctx, src);
584 return dst;
585}
586
587static void
588png_mask_transparency(struct info *info, fz_pixmap *dst)
589{
590 unsigned int stride = (info->width * info->n * info->depth + 7) / 8;
591 unsigned int depth = info->depth;
592 unsigned int n = info->n;
593 unsigned int x, y, k, t;
594
595 for (y = 0; y < info->height; y++)
596 {
597 unsigned char *sp = info->samples + (unsigned int)(y * stride);
598 unsigned char *dp = dst->samples + (unsigned int)(y * dst->stride);
599 for (x = 0; x < info->width; x++)
600 {
601 t = 1;
602 for (k = 0; k < n; k++)
603 if (getcomp(sp, x * n + k, depth) != info->trns[k])
604 t = 0;
605 if (t)
606 dp[x * dst->n + dst->n - 1] = 0;
607 }
608 }
609}
610
611fz_pixmap *
612fz_load_png(fz_context *ctx, const unsigned char *p, size_t total)
613{
614 fz_pixmap *image = NULL;
615 struct info png;
616 int stride;
617 int alpha;
618
619 fz_var(image);
620
621 fz_try(ctx)
622 {
623 png_read_image(ctx, &png, p, total, 0);
624
625 stride = (png.width * png.n * png.depth + 7) / 8;
626 alpha = (png.n == 2 || png.n == 4 || png.transparency);
627
628 if (png.indexed)
629 {
630 image = fz_new_pixmap(ctx, NULL, png.width, png.height, NULL, 1);
631 fz_unpack_tile(ctx, image, png.samples, png.n, png.depth, stride, 1);
632 image = png_expand_palette(ctx, &png, image);
633 }
634 else
635 {
636 image = fz_new_pixmap(ctx, png.cs, png.width, png.height, NULL, alpha);
637 fz_unpack_tile(ctx, image, png.samples, png.n, png.depth, stride, 0);
638 if (png.transparency)
639 png_mask_transparency(&png, image);
640 }
641 if (alpha)
642 fz_premultiply_pixmap(ctx, image);
643 fz_set_pixmap_resolution(ctx, image, png.xres, png.yres);
644 }
645 fz_always(ctx)
646 {
647 fz_drop_colorspace(ctx, png.cs);
648 fz_free(ctx, png.samples);
649 }
650 fz_catch(ctx)
651 {
652 fz_drop_pixmap(ctx, image);
653 fz_rethrow(ctx);
654 }
655
656 return image;
657}
658
659void
660fz_load_png_info(fz_context *ctx, const unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
661{
662 struct info png;
663
664 fz_try(ctx)
665 png_read_image(ctx, &png, p, total, 1);
666 fz_catch(ctx)
667 {
668 fz_drop_colorspace(ctx, png.cs);
669 fz_rethrow(ctx);
670 }
671
672 *cspacep = png.cs;
673 *wp = png.width;
674 *hp = png.height;
675 *xresp = png.xres;
676 *yresp = png.xres;
677}
678