]> git.sesse.net Git - ffmpeg/blob - libavformat/png.c
75d07ddcee89475d9c113038f2c7dff9365b10ed
[ffmpeg] / 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 #ifdef CONFIG_ZLIB
22 #include <zlib.h>
23
24 //#define DEBUG
25
26 #define PNG_COLOR_MASK_PALETTE    1
27 #define PNG_COLOR_MASK_COLOR      2
28 #define PNG_COLOR_MASK_ALPHA      4
29
30 #define PNG_COLOR_TYPE_GRAY 0
31 #define PNG_COLOR_TYPE_PALETTE  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
32 #define PNG_COLOR_TYPE_RGB        (PNG_COLOR_MASK_COLOR)
33 #define PNG_COLOR_TYPE_RGB_ALPHA  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
34 #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
35
36 #define PNG_FILTER_VALUE_NONE  0
37 #define PNG_FILTER_VALUE_SUB   1
38 #define PNG_FILTER_VALUE_UP    2
39 #define PNG_FILTER_VALUE_AVG   3
40 #define PNG_FILTER_VALUE_PAETH 4
41
42 #define PNG_IHDR      0x0001
43 #define PNG_IDAT      0x0002
44 #define PNG_ALLIMAGE  0x0004
45 #define PNG_PLTE      0x0008
46
47 #define IOBUF_SIZE 4096
48
49 typedef struct PNGDecodeState {
50     int state;
51     int width, height;
52     int bit_depth;
53     int color_type;
54     int compression_type;
55     int interlace_type;
56     int filter_type;
57     int channels;
58     int bits_per_pixel;
59     int bpp;
60     
61     uint8_t *image_buf;
62     int image_linesize;
63     uint32_t palette[256];
64     uint8_t *crow_buf;
65     uint8_t *empty_row;
66     int crow_size; /* compressed row size (include filter type) */
67     int row_size; /* decompressed row size */
68     int y;
69     z_stream zstream;
70 } PNGDecodeState;
71
72 static const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
73
74 static int png_probe(AVProbeData *pd)
75 {
76     if (pd->buf_size >= 8 &&
77         memcmp(pd->buf, pngsig, 8) == 0)
78         return AVPROBE_SCORE_MAX;
79     else
80         return 0;
81 }
82
83 static void *png_zalloc(void *opaque, unsigned int items, unsigned int size)
84 {
85     return av_malloc(items * size);
86 }
87
88 static void png_zfree(void *opaque, void *ptr)
89 {
90     av_free(ptr);
91 }
92
93 /* XXX: optimize */
94 static void png_filter_row(uint8_t *dst, int filter_type, 
95                            uint8_t *src, uint8_t *last, int size, int bpp)
96 {
97     int i, p;
98
99     switch(filter_type) {
100     case PNG_FILTER_VALUE_NONE:
101         memcpy(dst, src, size);
102         break;
103     case PNG_FILTER_VALUE_SUB:
104         for(i = 0; i < bpp; i++) {
105             dst[i] = src[i];
106         }
107         for(i = bpp; i < size; i++) {
108             p = dst[i - bpp];
109             dst[i] = p + src[i];
110         }
111         break;
112     case PNG_FILTER_VALUE_UP:
113         for(i = 0; i < size; i++) {
114             p = last[i];
115             dst[i] = p + src[i];
116         }
117         break;
118     case PNG_FILTER_VALUE_AVG:
119         for(i = 0; i < bpp; i++) {
120             p = (last[i] >> 1);
121             dst[i] = p + src[i];
122         }
123         for(i = bpp; i < size; i++) {
124             p = ((dst[i - bpp] + last[i]) >> 1);
125             dst[i] = p + src[i];
126         }
127         break;
128     case PNG_FILTER_VALUE_PAETH:
129         for(i = 0; i < bpp; i++) {
130             p = last[i];
131             dst[i] = p + src[i];
132         }
133         for(i = bpp; i < size; i++) {
134             int a, b, c, pa, pb, pc;
135
136             a = dst[i - bpp];
137             b = last[i];
138             c = last[i - bpp];
139
140             p = b - c;
141             pc = a - c;
142
143             pa = abs(p);
144             pb = abs(pc);
145             pc = abs(p + pc);
146
147             if (pa <= pb && pa <= pc)
148                 p = a;
149             else if (pb <= pc)
150                 p = b;
151             else
152                 p = c;
153             dst[i] = p + src[i];
154         }
155         break;
156     }
157 }
158
159 static void png_handle_row(PNGDecodeState *s)
160 {
161     uint8_t *ptr, *last_row;
162     ptr = s->image_buf + s->image_linesize * s->y;
163     if (s->y == 0)
164         last_row = s->empty_row;
165     else
166         last_row = ptr - s->image_linesize;
167
168     png_filter_row(ptr, s->crow_buf[0], s->crow_buf + 1, 
169                    last_row, s->row_size, s->bpp);
170 }
171
172 static int png_decode_idat(PNGDecodeState *s, ByteIOContext *f, int length)
173 {
174     uint8_t buf[IOBUF_SIZE];
175     int buf_size;
176     int ret;
177     while (length > 0) {
178         /* read the buffer */
179         buf_size = IOBUF_SIZE;
180         if (buf_size > length)
181             buf_size = length;
182         ret = get_buffer(f, buf, buf_size);
183         if (ret != buf_size)
184             return -1;
185         s->zstream.avail_in = buf_size;
186         s->zstream.next_in = buf;
187         /* decode one line if possible */
188         while (s->zstream.avail_in > 0) {
189             ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
190             if (ret != Z_OK && ret != Z_STREAM_END) {
191                 return -1;
192             }
193             if (s->zstream.avail_out == 0) {
194                 if (s->y < s->height) {
195                     png_handle_row(s);
196                     s->y++;
197                     if (s->y == s->height)
198                         s->state |= PNG_ALLIMAGE;
199                 }
200                 s->zstream.avail_out = s->crow_size;
201                 s->zstream.next_out = s->crow_buf;
202             }
203         }
204         length -= buf_size;
205     }
206     return 0;
207 }
208
209 static int png_read(ByteIOContext *f, 
210                     int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
211 {
212     AVImageInfo info1, *info = &info1;
213     PNGDecodeState s1, *s = &s1;
214     uint32_t tag, length;
215     int ret, crc;
216     uint8_t buf[8];
217
218     /* check signature */
219     ret = get_buffer(f, buf, 8);
220     if (ret != 8)
221         return -1;
222     if (memcmp(buf, pngsig, 8) != 0)
223         return -1;
224     memset(s, 0, sizeof(PNGDecodeState));
225     /* init the zlib */
226     s->zstream.zalloc = png_zalloc;
227     s->zstream.zfree = png_zfree;
228     s->zstream.opaque = NULL;
229     ret = inflateInit(&s->zstream);
230     if (ret != Z_OK)
231         return -1;
232     for(;;) {
233         if (url_feof(f))
234             goto fail;
235         length = get_be32(f);
236         if (length > 0x7fffffff)
237             goto fail;
238         tag = get_le32(f);
239 #ifdef DEBUG
240         printf("png: tag=%c%c%c%c length=%u\n", 
241                (tag & 0xff),
242                ((tag >> 8) & 0xff),
243                ((tag >> 16) & 0xff),
244                ((tag >> 24) & 0xff), length);
245 #endif
246         switch(tag) {
247         case MKTAG('I', 'H', 'D', 'R'):
248             if (length != 13)
249                 goto fail;
250             s->width = get_be32(f);
251             s->height = get_be32(f);
252             s->bit_depth = get_byte(f);
253             s->color_type = get_byte(f);
254             s->compression_type = get_byte(f);
255             s->filter_type = get_byte(f);
256             s->interlace_type = get_byte(f);
257             crc = get_be32(f);
258             s->state |= PNG_IHDR;
259 #ifdef DEBUG
260             printf("width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", 
261                    s->width, s->height, s->bit_depth, s->color_type, 
262                    s->compression_type, s->filter_type, s->interlace_type);
263 #endif
264             break;
265         case MKTAG('I', 'D', 'A', 'T'):
266             if (!(s->state & PNG_IHDR))
267                 goto fail;
268             if (!(s->state & PNG_IDAT)) {
269                 /* init image info */
270                 info->width = s->width;
271                 info->height = s->height;
272
273                 s->channels = 1;
274                 if ((s->color_type & (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)) ==
275                     PNG_COLOR_MASK_COLOR)
276                     s->channels = 3;
277                 if (s->color_type & PNG_COLOR_MASK_ALPHA)
278                     s->channels++;
279                 s->bits_per_pixel = s->bit_depth * s->channels;
280                 s->bpp = (s->bits_per_pixel + 7) >> 3;
281                 if (s->bit_depth == 8 && 
282                     s->color_type == PNG_COLOR_TYPE_RGB) {
283                     info->pix_fmt = PIX_FMT_RGB24;
284                     s->row_size = s->width * 3;
285                 } else if (s->bit_depth == 8 && 
286                            s->color_type == PNG_COLOR_TYPE_GRAY) {
287                     info->pix_fmt = PIX_FMT_GRAY8;
288                     s->row_size = s->width;
289                 } else if (s->bit_depth == 1 && 
290                            s->color_type == PNG_COLOR_TYPE_GRAY) {
291                     info->pix_fmt = PIX_FMT_MONOBLACK;
292                     s->row_size = (s->width + 7) >> 3;
293                 } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
294                     info->pix_fmt = PIX_FMT_PAL8;
295                     s->row_size = s->width;;
296                 } else {
297                     goto fail;
298                 }
299                 /* compute the compressed row size */
300                 if (!s->interlace_type) {
301                     s->crow_size = s->row_size + 1;
302                 } else {
303                     /* XXX: handle interlacing */
304                     goto fail;
305                 }
306                 ret = alloc_cb(opaque, info);
307                 if (ret) 
308                     goto the_end;
309 #ifdef DEBUG
310                 printf("row_size=%d crow_size =%d\n", 
311                        s->row_size, s->crow_size);
312 #endif
313                 s->image_buf = info->pict.data[0];
314                 s->image_linesize = info->pict.linesize[0];
315                 /* copy the palette if needed */
316                 if (s->color_type == PNG_COLOR_TYPE_PALETTE)
317                     memcpy(info->pict.data[1], s->palette, 256 * sizeof(uint32_t));
318                 /* empty row is used if differencing to the first row */
319                 s->empty_row = av_mallocz(s->row_size);
320                 if (!s->empty_row)
321                     goto fail;
322                 /* compressed row */
323                 s->crow_buf = av_malloc(s->crow_size);
324                 if (!s->crow_buf)
325                     goto fail;
326                 s->zstream.avail_out = s->crow_size;
327                 s->zstream.next_out = s->crow_buf;
328             }
329             s->state |= PNG_IDAT;
330             if (png_decode_idat(s, f, length) < 0)
331                 goto fail;
332             /* skip crc */
333             crc = get_be32(f);
334             break;
335         case MKTAG('P', 'L', 'T', 'E'):
336             {
337                 int n, i, r, g, b;
338                 
339                 if ((length % 3) != 0 || length > 256 * 3)
340                     goto skip_tag;
341                 /* read the palette */
342                 n = length / 3;
343                 for(i=0;i<n;i++) {
344                     r = get_byte(f);
345                     g = get_byte(f);
346                     b = get_byte(f);
347                     s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
348                 }
349                 for(;i<256;i++) {
350                     s->palette[i] = (0xff << 24);
351                 }
352                 s->state |= PNG_PLTE;
353                 crc = get_be32(f);
354             }
355             break;
356         case MKTAG('t', 'R', 'N', 'S'):
357             {
358                 int v, i;
359
360                 /* read the transparency. XXX: Only palette mode supported */
361                 if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
362                     length > 256 ||
363                     !(s->state & PNG_PLTE))
364                     goto skip_tag;
365                 for(i=0;i<length;i++) {
366                     v = get_byte(f);
367                     s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
368                 }
369                 crc = get_be32(f);
370             }
371             break;
372         case MKTAG('I', 'E', 'N', 'D'):
373             if (!(s->state & PNG_ALLIMAGE))
374                 goto fail;
375             crc = get_be32(f);
376             goto exit_loop;
377         default:
378             /* skip tag */
379         skip_tag:
380             url_fskip(f, length + 4);
381             break;
382         }
383     }
384  exit_loop:
385     ret = 0;
386  the_end:
387     inflateEnd(&s->zstream);
388     av_free(s->crow_buf);
389     return ret;
390  fail:
391     ret = -1;
392     goto the_end;
393 }
394
395 static void png_write_chunk(ByteIOContext *f, uint32_t tag,
396                             const uint8_t *buf, int length)
397 {
398     uint32_t crc;
399     uint8_t tagbuf[4];
400
401     put_be32(f, length);
402     crc = crc32(0, Z_NULL, 0);
403     tagbuf[0] = tag;
404     tagbuf[1] = tag >> 8;
405     tagbuf[2] = tag >> 16;
406     tagbuf[3] = tag >> 24;
407     crc = crc32(crc, tagbuf, 4);
408     put_le32(f, tag);
409     if (length > 0) {
410         crc = crc32(crc, buf, length);
411         put_buffer(f, buf, length);
412     }
413     put_be32(f, crc);
414 }
415
416 /* XXX: use avcodec generic function ? */
417 static void to_be32(uint8_t *p, uint32_t v)
418 {
419     p[0] = v >> 24;
420     p[1] = v >> 16;
421     p[2] = v >> 8;
422     p[3] = v;
423 }
424
425 static int png_write(ByteIOContext *f, AVImageInfo *info)
426 {
427     int bit_depth, color_type, y, len, row_size, ret;
428     uint8_t *ptr;
429     uint8_t buf[IOBUF_SIZE];
430     uint8_t *crow_buf = NULL;
431     z_stream zstream;
432     
433     switch(info->pix_fmt) {
434     case PIX_FMT_RGB24:
435         bit_depth = 8;
436         color_type = PNG_COLOR_TYPE_RGB;
437         row_size = info->width * 3;
438         break;
439     case PIX_FMT_GRAY8:
440         bit_depth = 8;
441         color_type = PNG_COLOR_TYPE_GRAY;
442         row_size = info->width;
443         break;
444     case PIX_FMT_MONOBLACK:
445         bit_depth = 1;
446         color_type = PNG_COLOR_TYPE_GRAY;
447         row_size = (info->width + 7) >> 3;
448         break;
449     case PIX_FMT_PAL8:
450         bit_depth = 8;
451         color_type = PNG_COLOR_TYPE_PALETTE;
452         row_size = info->width;
453         break;
454     default:
455         return -1;
456     }
457     zstream.zalloc = png_zalloc;
458     zstream.zfree = png_zfree;
459     zstream.opaque = NULL;
460     ret = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION,
461                        Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY);
462     if (ret != Z_OK)
463         return -1;
464     crow_buf = av_malloc(row_size + 1);
465     if (!crow_buf)
466         goto fail;
467
468     /* write png header */
469     put_buffer(f, pngsig, 8);
470     
471     to_be32(buf, info->width);
472     to_be32(buf + 4, info->height);
473     buf[8] = bit_depth;
474     buf[9] = color_type;
475     buf[10] = 0; /* compression type */
476     buf[11] = 0; /* filter type */
477     buf[12] = 0; /* interlace type */
478     
479     png_write_chunk(f, MKTAG('I', 'H', 'D', 'R'), buf, 13);
480
481     /* put the palette if needed */
482     if (color_type == PNG_COLOR_TYPE_PALETTE) {
483         int has_alpha, alpha, i;
484         unsigned int v;
485         uint32_t *palette;
486         uint8_t *alpha_ptr;
487         
488         palette = (uint32_t *)info->pict.data[1];
489         ptr = buf;
490         alpha_ptr = buf + 256 * 3;
491         has_alpha = 0;
492         for(i = 0; i < 256; i++) {
493             v = palette[i];
494             alpha = v >> 24;
495             if (alpha != 0xff)
496                 has_alpha = 1;
497             *alpha_ptr++ = alpha;
498             ptr[0] = v >> 16;
499             ptr[1] = v >> 8;
500             ptr[2] = v;
501             ptr += 3;
502         }
503         png_write_chunk(f, MKTAG('P', 'L', 'T', 'E'), buf, 256 * 3);
504         if (has_alpha) {
505             png_write_chunk(f, MKTAG('t', 'R', 'N', 'S'), buf + 256 * 3, 256);
506         }
507     }
508
509     /* now put each row */
510     zstream.avail_out = IOBUF_SIZE;
511     zstream.next_out = buf;
512     for(y = 0;y < info->height; y++) {
513         /* XXX: do filtering */
514         ptr = info->pict.data[0] + y * info->pict.linesize[0];
515         memcpy(crow_buf + 1, ptr, row_size);
516         crow_buf[0] = PNG_FILTER_VALUE_NONE;
517         zstream.avail_in = row_size + 1;
518         zstream.next_in = crow_buf;
519         while (zstream.avail_in > 0) {
520             ret = deflate(&zstream, Z_NO_FLUSH);
521             if (ret != Z_OK)
522                 goto fail;
523             if (zstream.avail_out == 0) {
524                 png_write_chunk(f, MKTAG('I', 'D', 'A', 'T'), buf, IOBUF_SIZE);
525                 zstream.avail_out = IOBUF_SIZE;
526                 zstream.next_out = buf;
527             }
528         }
529     }
530     /* compress last bytes */
531     for(;;) {
532         ret = deflate(&zstream, Z_FINISH);
533         if (ret == Z_OK || ret == Z_STREAM_END) {
534             len = IOBUF_SIZE - zstream.avail_out;
535             if (len > 0) {
536                 png_write_chunk(f, MKTAG('I', 'D', 'A', 'T'), buf, len);
537             }
538             zstream.avail_out = IOBUF_SIZE;
539             zstream.next_out = buf;
540             if (ret == Z_STREAM_END)
541                 break;
542         } else {
543             goto fail;
544         }
545     }
546     png_write_chunk(f, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
547
548     put_flush_packet(f);
549     ret = 0;
550  the_end:
551     av_free(crow_buf);
552     deflateEnd(&zstream);
553     return ret;
554  fail:
555     ret = -1;
556     goto the_end;
557 }
558
559 AVImageFormat png_image_format = {
560     "png",
561     "png",
562     png_probe,
563     png_read,
564     (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_MONOBLACK) | (1 << PIX_FMT_PAL8),
565     png_write,
566 };
567 #endif