af4694b11229a0b9d77444883d85ddba433bbe50
[libav.git] / libavformat / png.c
1 /*
2 * PNG image format
3 * Copyright (c) 2003 Fabrice Bellard.
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 #include "avformat.h"
22
23 /* TODO:
24 * - add 2, 4 and 16 bit depth support
25 * - use filters when generating a png (better compression)
26 */
27
28 #include <zlib.h>
29
30 //#define DEBUG
31
32 #define PNG_COLOR_MASK_PALETTE 1
33 #define PNG_COLOR_MASK_COLOR 2
34 #define PNG_COLOR_MASK_ALPHA 4
35
36 #define PNG_COLOR_TYPE_GRAY 0
37 #define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
38 #define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
39 #define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
40 #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
41
42 #define PNG_FILTER_VALUE_NONE 0
43 #define PNG_FILTER_VALUE_SUB 1
44 #define PNG_FILTER_VALUE_UP 2
45 #define PNG_FILTER_VALUE_AVG 3
46 #define PNG_FILTER_VALUE_PAETH 4
47
48 #define PNG_IHDR 0x0001
49 #define PNG_IDAT 0x0002
50 #define PNG_ALLIMAGE 0x0004
51 #define PNG_PLTE 0x0008
52
53 #define NB_PASSES 7
54
55 #define IOBUF_SIZE 4096
56
57 typedef struct PNGDecodeState {
58 int state;
59 int width, height;
60 int bit_depth;
61 int color_type;
62 int compression_type;
63 int interlace_type;
64 int filter_type;
65 int channels;
66 int bits_per_pixel;
67 int bpp;
68
69 uint8_t *image_buf;
70 int image_linesize;
71 uint32_t palette[256];
72 uint8_t *crow_buf;
73 uint8_t *last_row;
74 uint8_t *tmp_row;
75 int pass;
76 int crow_size; /* compressed row size (include filter type) */
77 int row_size; /* decompressed row size */
78 int pass_row_size; /* decompress row size of the current pass */
79 int y;
80 z_stream zstream;
81 } PNGDecodeState;
82
83 static const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
84
85 /* Mask to determine which y pixels are valid in a pass */
86 static const uint8_t png_pass_ymask[NB_PASSES] = {
87 0x80, 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55,
88 };
89
90 /* Mask to determine which y pixels can be written in a pass */
91 static const uint8_t png_pass_dsp_ymask[NB_PASSES] = {
92 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55,
93 };
94
95 /* minimum x value */
96 static const uint8_t png_pass_xmin[NB_PASSES] = {
97 0, 4, 0, 2, 0, 1, 0
98 };
99
100 /* x shift to get row width */
101 static const uint8_t png_pass_xshift[NB_PASSES] = {
102 3, 3, 2, 2, 1, 1, 0
103 };
104
105 /* Mask to determine which pixels are valid in a pass */
106 static const uint8_t png_pass_mask[NB_PASSES] = {
107 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff
108 };
109
110 /* Mask to determine which pixels to overwrite while displaying */
111 static const uint8_t png_pass_dsp_mask[NB_PASSES] = {
112 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff
113 };
114
115 static int png_probe(AVProbeData *pd)
116 {
117 if (pd->buf_size >= 8 &&
118 memcmp(pd->buf, pngsig, 8) == 0)
119 return AVPROBE_SCORE_MAX;
120 else
121 return 0;
122 }
123
124 static void *png_zalloc(void *opaque, unsigned int items, unsigned int size)
125 {
126 return av_malloc(items * size);
127 }
128
129 static void png_zfree(void *opaque, void *ptr)
130 {
131 av_free(ptr);
132 }
133
134 static int png_get_nb_channels(int color_type)
135 {
136 int channels;
137 channels = 1;
138 if ((color_type & (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)) ==
139 PNG_COLOR_MASK_COLOR)
140 channels = 3;
141 if (color_type & PNG_COLOR_MASK_ALPHA)
142 channels++;
143 return channels;
144 }
145
146 /* compute the row size of an interleaved pass */
147 static int png_pass_row_size(int pass, int bits_per_pixel, int width)
148 {
149 int shift, xmin, pass_width;
150
151 xmin = png_pass_xmin[pass];
152 if (width <= xmin)
153 return 0;
154 shift = png_pass_xshift[pass];
155 pass_width = (width - xmin + (1 << shift) - 1) >> shift;
156 return (pass_width * bits_per_pixel + 7) >> 3;
157 }
158
159 /* NOTE: we try to construct a good looking image at each pass. width
160 is the original image width. We also do pixel format convertion at
161 this stage */
162 static void png_put_interlaced_row(uint8_t *dst, int width,
163 int bits_per_pixel, int pass,
164 int color_type, const uint8_t *src)
165 {
166 int x, mask, dsp_mask, j, src_x, b, bpp;
167 uint8_t *d;
168 const uint8_t *s;
169
170 mask = png_pass_mask[pass];
171 dsp_mask = png_pass_dsp_mask[pass];
172 switch(bits_per_pixel) {
173 case 1:
174 /* we must intialize the line to zero before writing to it */
175 if (pass == 0)
176 memset(dst, 0, (width + 7) >> 3);
177 src_x = 0;
178 for(x = 0; x < width; x++) {
179 j = (x & 7);
180 if ((dsp_mask << j) & 0x80) {
181 b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1;
182 dst[x >> 3] |= b << (7 - j);
183 }
184 if ((mask << j) & 0x80)
185 src_x++;
186 }
187 break;
188 default:
189 bpp = bits_per_pixel >> 3;
190 d = dst;
191 s = src;
192 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
193 for(x = 0; x < width; x++) {
194 j = x & 7;
195 if ((dsp_mask << j) & 0x80) {
196 *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2];
197 }
198 d += bpp;
199 if ((mask << j) & 0x80)
200 s += bpp;
201 }
202 } else {
203 for(x = 0; x < width; x++) {
204 j = x & 7;
205 if ((dsp_mask << j) & 0x80) {
206 memcpy(d, s, bpp);
207 }
208 d += bpp;
209 if ((mask << j) & 0x80)
210 s += bpp;
211 }
212 }
213 break;
214 }
215 }
216
217 static void png_get_interlaced_row(uint8_t *dst, int row_size,
218 int bits_per_pixel, int pass,
219 const uint8_t *src, int width)
220 {
221 int x, mask, dst_x, j, b, bpp;
222 uint8_t *d;
223 const uint8_t *s;
224
225 mask = png_pass_mask[pass];
226 switch(bits_per_pixel) {
227 case 1:
228 memset(dst, 0, row_size);
229 dst_x = 0;
230 for(x = 0; x < width; x++) {
231 j = (x & 7);
232 if ((mask << j) & 0x80) {
233 b = (src[x >> 3] >> (7 - j)) & 1;
234 dst[dst_x >> 3] |= b << (7 - (dst_x & 7));
235 dst_x++;
236 }
237 }
238 break;
239 default:
240 bpp = bits_per_pixel >> 3;
241 d = dst;
242 s = src;
243 for(x = 0; x < width; x++) {
244 j = x & 7;
245 if ((mask << j) & 0x80) {
246 memcpy(d, s, bpp);
247 d += bpp;
248 }
249 s += bpp;
250 }
251 break;
252 }
253 }
254
255 /* XXX: optimize */
256 /* NOTE: 'dst' can be equal to 'last' */
257 static void png_filter_row(uint8_t *dst, int filter_type,
258 uint8_t *src, uint8_t *last, int size, int bpp)
259 {
260 int i, p;
261
262 switch(filter_type) {
263 case PNG_FILTER_VALUE_NONE:
264 memcpy(dst, src, size);
265 break;
266 case PNG_FILTER_VALUE_SUB:
267 for(i = 0; i < bpp; i++) {
268 dst[i] = src[i];
269 }
270 for(i = bpp; i < size; i++) {
271 p = dst[i - bpp];
272 dst[i] = p + src[i];
273 }
274 break;
275 case PNG_FILTER_VALUE_UP:
276 for(i = 0; i < size; i++) {
277 p = last[i];
278 dst[i] = p + src[i];
279 }
280 break;
281 case PNG_FILTER_VALUE_AVG:
282 for(i = 0; i < bpp; i++) {
283 p = (last[i] >> 1);
284 dst[i] = p + src[i];
285 }
286 for(i = bpp; i < size; i++) {
287 p = ((dst[i - bpp] + last[i]) >> 1);
288 dst[i] = p + src[i];
289 }
290 break;
291 case PNG_FILTER_VALUE_PAETH:
292 for(i = 0; i < bpp; i++) {
293 p = last[i];
294 dst[i] = p + src[i];
295 }
296 for(i = bpp; i < size; i++) {
297 int a, b, c, pa, pb, pc;
298
299 a = dst[i - bpp];
300 b = last[i];
301 c = last[i - bpp];
302
303 p = b - c;
304 pc = a - c;
305
306 pa = abs(p);
307 pb = abs(pc);
308 pc = abs(p + pc);
309
310 if (pa <= pb && pa <= pc)
311 p = a;
312 else if (pb <= pc)
313 p = b;
314 else
315 p = c;
316 dst[i] = p + src[i];
317 }
318 break;
319 }
320 }
321
322 static void convert_from_rgba32(uint8_t *dst, const uint8_t *src, int width)
323 {
324 uint8_t *d;
325 int j;
326 unsigned int v;
327
328 d = dst;
329 for(j = 0; j < width; j++) {
330 v = ((const uint32_t *)src)[j];
331 d[0] = v >> 16;
332 d[1] = v >> 8;
333 d[2] = v;
334 d[3] = v >> 24;
335 d += 4;
336 }
337 }
338
339 static void convert_to_rgba32(uint8_t *dst, const uint8_t *src, int width)
340 {
341 int j;
342 unsigned int r, g, b, a;
343
344 for(j = 0;j < width; j++) {
345 r = src[0];
346 g = src[1];
347 b = src[2];
348 a = src[3];
349 *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b;
350 dst += 4;
351 src += 4;
352 }
353 }
354
355 /* process exactly one decompressed row */
356 static void png_handle_row(PNGDecodeState *s)
357 {
358 uint8_t *ptr, *last_row;
359 int got_line;
360
361 if (!s->interlace_type) {
362 ptr = s->image_buf + s->image_linesize * s->y;
363 /* need to swap bytes correctly for RGB_ALPHA */
364 if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
365 png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
366 s->last_row, s->row_size, s->bpp);
367 memcpy(s->last_row, s->tmp_row, s->row_size);
368 convert_to_rgba32(ptr, s->tmp_row, s->width);
369 } else {
370 /* in normal case, we avoid one copy */
371 if (s->y == 0)
372 last_row = s->last_row;
373 else
374 last_row = ptr - s->image_linesize;
375
376 png_filter_row(ptr, s->crow_buf[0], s->crow_buf + 1,
377 last_row, s->row_size, s->bpp);
378 }
379 s->y++;
380 if (s->y == s->height) {
381 s->state |= PNG_ALLIMAGE;
382 }
383 } else {
384 got_line = 0;
385 for(;;) {
386 ptr = s->image_buf + s->image_linesize * s->y;
387 if ((png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) {
388 /* if we already read one row, it is time to stop to
389 wait for the next one */
390 if (got_line)
391 break;
392 png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
393 s->last_row, s->pass_row_size, s->bpp);
394 memcpy(s->last_row, s->tmp_row, s->pass_row_size);
395 got_line = 1;
396 }
397 if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) {
398 /* NOTE: rgba32 is handled directly in png_put_interlaced_row */
399 png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass,
400 s->color_type, s->last_row);
401 }
402 s->y++;
403 if (s->y == s->height) {
404 for(;;) {
405 if (s->pass == NB_PASSES - 1) {
406 s->state |= PNG_ALLIMAGE;
407 goto the_end;
408 } else {
409 s->pass++;
410 s->y = 0;
411 s->pass_row_size = png_pass_row_size(s->pass,
412 s->bits_per_pixel,
413 s->width);
414 s->crow_size = s->pass_row_size + 1;
415 if (s->pass_row_size != 0)
416 break;
417 /* skip pass if empty row */
418 }
419 }
420 }
421 }
422 the_end: ;
423 }
424 }
425
426 static int png_decode_idat(PNGDecodeState *s, ByteIOContext *f, int length)
427 {
428 uint8_t buf[IOBUF_SIZE];
429 int buf_size;
430 int ret;
431 while (length > 0) {
432 /* read the buffer */
433 buf_size = IOBUF_SIZE;
434 if (buf_size > length)
435 buf_size = length;
436 ret = get_buffer(f, buf, buf_size);
437 if (ret != buf_size)
438 return -1;
439 s->zstream.avail_in = buf_size;
440 s->zstream.next_in = buf;
441 /* decode one line if possible */
442 while (s->zstream.avail_in > 0) {
443 ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
444 if (ret != Z_OK && ret != Z_STREAM_END) {
445 return -1;
446 }
447 if (s->zstream.avail_out == 0) {
448 if (!(s->state & PNG_ALLIMAGE)) {
449 png_handle_row(s);
450 }
451 s->zstream.avail_out = s->crow_size;
452 s->zstream.next_out = s->crow_buf;
453 }
454 }
455 length -= buf_size;
456 }
457 return 0;
458 }
459
460 static int png_read(ByteIOContext *f,
461 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
462 {
463 AVImageInfo info1, *info = &info1;
464 PNGDecodeState s1, *s = &s1;
465 uint32_t tag, length;
466 int ret, crc;
467 uint8_t buf[8];
468
469 /* check signature */
470 ret = get_buffer(f, buf, 8);
471 if (ret != 8)
472 return -1;
473 if (memcmp(buf, pngsig, 8) != 0)
474 return -1;
475 memset(s, 0, sizeof(PNGDecodeState));
476 /* init the zlib */
477 s->zstream.zalloc = png_zalloc;
478 s->zstream.zfree = png_zfree;
479 s->zstream.opaque = NULL;
480 ret = inflateInit(&s->zstream);
481 if (ret != Z_OK)
482 return -1;
483 for(;;) {
484 if (url_feof(f))
485 goto fail;
486 length = get_be32(f);
487 if (length > 0x7fffffff)
488 goto fail;
489 tag = get_le32(f);
490 #ifdef DEBUG
491 printf("png: tag=%c%c%c%c length=%u\n",
492 (tag & 0xff),
493 ((tag >> 8) & 0xff),
494 ((tag >> 16) & 0xff),
495 ((tag >> 24) & 0xff), length);
496 #endif
497 switch(tag) {
498 case MKTAG('I', 'H', 'D', 'R'):
499 if (length != 13)
500 goto fail;
501 s->width = get_be32(f);
502 s->height = get_be32(f);
503 s->bit_depth = get_byte(f);
504 s->color_type = get_byte(f);
505 s->compression_type = get_byte(f);
506 s->filter_type = get_byte(f);
507 s->interlace_type = get_byte(f);
508 crc = get_be32(f);
509 s->state |= PNG_IHDR;
510 #ifdef DEBUG
511 printf("width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n",
512 s->width, s->height, s->bit_depth, s->color_type,
513 s->compression_type, s->filter_type, s->interlace_type);
514 #endif
515 break;
516 case MKTAG('I', 'D', 'A', 'T'):
517 if (!(s->state & PNG_IHDR))
518 goto fail;
519 if (!(s->state & PNG_IDAT)) {
520 /* init image info */
521 info->width = s->width;
522 info->height = s->height;
523 info->interleaved = (s->interlace_type != 0);
524
525 s->channels = png_get_nb_channels(s->color_type);
526 s->bits_per_pixel = s->bit_depth * s->channels;
527 s->bpp = (s->bits_per_pixel + 7) >> 3;
528 s->row_size = (info->width * s->bits_per_pixel + 7) >> 3;
529
530 if (s->bit_depth == 8 &&
531 s->color_type == PNG_COLOR_TYPE_RGB) {
532 info->pix_fmt = PIX_FMT_RGB24;
533 } else if (s->bit_depth == 8 &&
534 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
535 info->pix_fmt = PIX_FMT_RGBA32;
536 } else if (s->bit_depth == 8 &&
537 s->color_type == PNG_COLOR_TYPE_GRAY) {
538 info->pix_fmt = PIX_FMT_GRAY8;
539 } else if (s->bit_depth == 1 &&
540 s->color_type == PNG_COLOR_TYPE_GRAY) {
541 info->pix_fmt = PIX_FMT_MONOBLACK;
542 } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
543 info->pix_fmt = PIX_FMT_PAL8;
544 } else {
545 goto fail;
546 }
547 ret = alloc_cb(opaque, info);
548 if (ret)
549 goto the_end;
550
551 /* compute the compressed row size */
552 if (!s->interlace_type) {
553 s->crow_size = s->row_size + 1;
554 } else {
555 s->pass = 0;
556 s->pass_row_size = png_pass_row_size(s->pass,
557 s->bits_per_pixel,
558 s->width);
559 s->crow_size = s->pass_row_size + 1;
560 }
561 #ifdef DEBUG
562 printf("row_size=%d crow_size =%d\n",
563 s->row_size, s->crow_size);
564 #endif
565 s->image_buf = info->pict.data[0];
566 s->image_linesize = info->pict.linesize[0];
567 /* copy the palette if needed */
568 if (s->color_type == PNG_COLOR_TYPE_PALETTE)
569 memcpy(info->pict.data[1], s->palette, 256 * sizeof(uint32_t));
570 /* empty row is used if differencing to the first row */
571 s->last_row = av_mallocz(s->row_size);
572 if (!s->last_row)
573 goto fail;
574 if (s->interlace_type ||
575 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
576 s->tmp_row = av_malloc(s->row_size);
577 if (!s->tmp_row)
578 goto fail;
579 }
580 /* compressed row */
581 s->crow_buf = av_malloc(s->row_size + 1);
582 if (!s->crow_buf)
583 goto fail;
584 s->zstream.avail_out = s->crow_size;
585 s->zstream.next_out = s->crow_buf;
586 }
587 s->state |= PNG_IDAT;
588 if (png_decode_idat(s, f, length) < 0)
589 goto fail;
590 /* skip crc */
591 crc = get_be32(f);
592 break;
593 case MKTAG('P', 'L', 'T', 'E'):
594 {
595 int n, i, r, g, b;
596
597 if ((length % 3) != 0 || length > 256 * 3)
598 goto skip_tag;
599 /* read the palette */
600 n = length / 3;
601 for(i=0;i<n;i++) {
602 r = get_byte(f);
603 g = get_byte(f);
604 b = get_byte(f);
605 s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
606 }
607 for(;i<256;i++) {
608 s->palette[i] = (0xff << 24);
609 }
610 s->state |= PNG_PLTE;
611 crc = get_be32(f);
612 }
613 break;
614 case MKTAG('t', 'R', 'N', 'S'):
615 {
616 int v, i;
617
618 /* read the transparency. XXX: Only palette mode supported */
619 if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
620 length > 256 ||
621 !(s->state & PNG_PLTE))
622 goto skip_tag;
623 for(i=0;i<length;i++) {
624 v = get_byte(f);
625 s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
626 }
627 crc = get_be32(f);
628 }
629 break;
630 case MKTAG('I', 'E', 'N', 'D'):
631 if (!(s->state & PNG_ALLIMAGE))
632 goto fail;
633 crc = get_be32(f);
634 goto exit_loop;
635 default:
636 /* skip tag */
637 skip_tag:
638 url_fskip(f, length + 4);
639 break;
640 }
641 }
642 exit_loop:
643 ret = 0;
644 the_end:
645 inflateEnd(&s->zstream);
646 av_free(s->crow_buf);
647 av_free(s->last_row);
648 av_free(s->tmp_row);
649 return ret;
650 fail:
651 ret = -1;
652 goto the_end;
653 }
654
655 static void png_write_chunk(ByteIOContext *f, uint32_t tag,
656 const uint8_t *buf, int length)
657 {
658 uint32_t crc;
659 uint8_t tagbuf[4];
660
661 put_be32(f, length);
662 crc = crc32(0, Z_NULL, 0);
663 tagbuf[0] = tag;
664 tagbuf[1] = tag >> 8;
665 tagbuf[2] = tag >> 16;
666 tagbuf[3] = tag >> 24;
667 crc = crc32(crc, tagbuf, 4);
668 put_le32(f, tag);
669 if (length > 0) {
670 crc = crc32(crc, buf, length);
671 put_buffer(f, buf, length);
672 }
673 put_be32(f, crc);
674 }
675
676 /* XXX: use avcodec generic function ? */
677 static void to_be32(uint8_t *p, uint32_t v)
678 {
679 p[0] = v >> 24;
680 p[1] = v >> 16;
681 p[2] = v >> 8;
682 p[3] = v;
683 }
684
685 typedef struct PNGEncodeState {
686 ByteIOContext *f;
687 z_stream zstream;
688 uint8_t buf[IOBUF_SIZE];
689 } PNGEncodeState;
690
691
692 /* XXX: do filtering */
693 static int png_write_row(PNGEncodeState *s, const uint8_t *data, int size)
694 {
695 int ret;
696
697 s->zstream.avail_in = size;
698 s->zstream.next_in = (uint8_t *)data;
699 while (s->zstream.avail_in > 0) {
700 ret = deflate(&s->zstream, Z_NO_FLUSH);
701 if (ret != Z_OK)
702 return -1;
703 if (s->zstream.avail_out == 0) {
704 png_write_chunk(s->f, MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE);
705 s->zstream.avail_out = IOBUF_SIZE;
706 s->zstream.next_out = s->buf;
707 }
708 }
709 return 0;
710 }
711
712 static int png_write(ByteIOContext *f, AVImageInfo *info)
713 {
714 PNGEncodeState s1, *s = &s1;
715 int bit_depth, color_type, y, len, row_size, ret, is_progressive;
716 int bits_per_pixel, pass_row_size;
717 uint8_t *ptr;
718 uint8_t *crow_buf = NULL;
719 uint8_t *tmp_buf = NULL;
720
721 s->f = f;
722 is_progressive = info->interleaved;
723 switch(info->pix_fmt) {
724 case PIX_FMT_RGBA32:
725 bit_depth = 8;
726 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
727 break;
728 case PIX_FMT_RGB24:
729 bit_depth = 8;
730 color_type = PNG_COLOR_TYPE_RGB;
731 break;
732 case PIX_FMT_GRAY8:
733 bit_depth = 8;
734 color_type = PNG_COLOR_TYPE_GRAY;
735 break;
736 case PIX_FMT_MONOBLACK:
737 bit_depth = 1;
738 color_type = PNG_COLOR_TYPE_GRAY;
739 break;
740 case PIX_FMT_PAL8:
741 bit_depth = 8;
742 color_type = PNG_COLOR_TYPE_PALETTE;
743 break;
744 default:
745 return -1;
746 }
747 bits_per_pixel = png_get_nb_channels(color_type) * bit_depth;
748 row_size = (info->width * bits_per_pixel + 7) >> 3;
749
750 s->zstream.zalloc = png_zalloc;
751 s->zstream.zfree = png_zfree;
752 s->zstream.opaque = NULL;
753 ret = deflateInit2(&s->zstream, Z_DEFAULT_COMPRESSION,
754 Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY);
755 if (ret != Z_OK)
756 return -1;
757 crow_buf = av_malloc(row_size + 1);
758 if (!crow_buf)
759 goto fail;
760 if (is_progressive) {
761 tmp_buf = av_malloc(row_size + 1);
762 if (!tmp_buf)
763 goto fail;
764 }
765
766 /* write png header */
767 put_buffer(f, pngsig, 8);
768
769 to_be32(s->buf, info->width);
770 to_be32(s->buf + 4, info->height);
771 s->buf[8] = bit_depth;
772 s->buf[9] = color_type;
773 s->buf[10] = 0; /* compression type */
774 s->buf[11] = 0; /* filter type */
775 s->buf[12] = is_progressive; /* interlace type */
776
777 png_write_chunk(f, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
778
779 /* put the palette if needed */
780 if (color_type == PNG_COLOR_TYPE_PALETTE) {
781 int has_alpha, alpha, i;
782 unsigned int v;
783 uint32_t *palette;
784 uint8_t *alpha_ptr;
785
786 palette = (uint32_t *)info->pict.data[1];
787 ptr = s->buf;
788 alpha_ptr = s->buf + 256 * 3;
789 has_alpha = 0;
790 for(i = 0; i < 256; i++) {
791 v = palette[i];
792 alpha = v >> 24;
793 if (alpha != 0xff)
794 has_alpha = 1;
795 *alpha_ptr++ = alpha;
796 ptr[0] = v >> 16;
797 ptr[1] = v >> 8;
798 ptr[2] = v;
799 ptr += 3;
800 }
801 png_write_chunk(f, MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3);
802 if (has_alpha) {
803 png_write_chunk(f, MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256);
804 }
805 }
806
807 /* now put each row */
808 s->zstream.avail_out = IOBUF_SIZE;
809 s->zstream.next_out = s->buf;
810 if (is_progressive) {
811 uint8_t *ptr1;
812 int pass;
813
814 for(pass = 0; pass < NB_PASSES; pass++) {
815 /* NOTE: a pass is completely omited if no pixels would be
816 output */
817 pass_row_size = png_pass_row_size(pass, bits_per_pixel, info->width);
818 if (pass_row_size > 0) {
819 for(y = 0; y < info->height; y++) {
820 if ((png_pass_ymask[pass] << (y & 7)) & 0x80) {
821 ptr = info->pict.data[0] + y * info->pict.linesize[0];
822 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
823 convert_from_rgba32(tmp_buf, ptr, info->width);
824 ptr1 = tmp_buf;
825 } else {
826 ptr1 = ptr;
827 }
828 png_get_interlaced_row(crow_buf + 1, pass_row_size,
829 bits_per_pixel, pass,
830 ptr1, info->width);
831 crow_buf[0] = PNG_FILTER_VALUE_NONE;
832 png_write_row(s, crow_buf, pass_row_size + 1);
833 }
834 }
835 }
836 }
837 } else {
838 for(y = 0; y < info->height; y++) {
839 ptr = info->pict.data[0] + y * info->pict.linesize[0];
840 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
841 convert_from_rgba32(crow_buf + 1, ptr, info->width);
842 else
843 memcpy(crow_buf + 1, ptr, row_size);
844 crow_buf[0] = PNG_FILTER_VALUE_NONE;
845 png_write_row(s, crow_buf, row_size + 1);
846 }
847 }
848 /* compress last bytes */
849 for(;;) {
850 ret = deflate(&s->zstream, Z_FINISH);
851 if (ret == Z_OK || ret == Z_STREAM_END) {
852 len = IOBUF_SIZE - s->zstream.avail_out;
853 if (len > 0) {
854 png_write_chunk(f, MKTAG('I', 'D', 'A', 'T'), s->buf, len);
855 }
856 s->zstream.avail_out = IOBUF_SIZE;
857 s->zstream.next_out = s->buf;
858 if (ret == Z_STREAM_END)
859 break;
860 } else {
861 goto fail;
862 }
863 }
864 png_write_chunk(f, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
865
866 put_flush_packet(f);
867 ret = 0;
868 the_end:
869 av_free(crow_buf);
870 av_free(tmp_buf);
871 deflateEnd(&s->zstream);
872 return ret;
873 fail:
874 ret = -1;
875 goto the_end;
876 }
877
878 AVImageFormat png_image_format = {
879 "png",
880 "png",
881 png_probe,
882 png_read,
883 (1 << PIX_FMT_RGBA32) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_GRAY8) |
884 (1 << PIX_FMT_MONOBLACK) | (1 << PIX_FMT_PAL8),
885 png_write,
886 AVIMAGE_INTERLEAVED,
887 };