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