Statistics
| Branch: | Revision:

ffmpeg / libavformat / png.c @ 8b46d75e

History | View | Annotate | Download (18.5 KB)

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
    uint8_t *tmp_row;
67
    int crow_size; /* compressed row size (include filter type) */
68
    int row_size; /* decompressed row size */
69
    int y;
70
    z_stream zstream;
71
} PNGDecodeState;
72

    
73
static const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
74

    
75
static int png_probe(AVProbeData *pd)
76
{
77
    if (pd->buf_size >= 8 &&
78
        memcmp(pd->buf, pngsig, 8) == 0)
79
        return AVPROBE_SCORE_MAX;
80
    else
81
        return 0;
82
}
83

    
84
static void *png_zalloc(void *opaque, unsigned int items, unsigned int size)
85
{
86
    return av_malloc(items * size);
87
}
88

    
89
static void png_zfree(void *opaque, void *ptr)
90
{
91
    av_free(ptr);
92
}
93

    
94
/* XXX: optimize */
95
/* NOTE: 'dst' can be equal to 'last' */
96
static void png_filter_row(uint8_t *dst, int filter_type, 
97
                           uint8_t *src, uint8_t *last, int size, int bpp)
98
{
99
    int i, p;
100

    
101
    switch(filter_type) {
102
    case PNG_FILTER_VALUE_NONE:
103
        memcpy(dst, src, size);
104
        break;
105
    case PNG_FILTER_VALUE_SUB:
106
        for(i = 0; i < bpp; i++) {
107
            dst[i] = src[i];
108
        }
109
        for(i = bpp; i < size; i++) {
110
            p = dst[i - bpp];
111
            dst[i] = p + src[i];
112
        }
113
        break;
114
    case PNG_FILTER_VALUE_UP:
115
        for(i = 0; i < size; i++) {
116
            p = last[i];
117
            dst[i] = p + src[i];
118
        }
119
        break;
120
    case PNG_FILTER_VALUE_AVG:
121
        for(i = 0; i < bpp; i++) {
122
            p = (last[i] >> 1);
123
            dst[i] = p + src[i];
124
        }
125
        for(i = bpp; i < size; i++) {
126
            p = ((dst[i - bpp] + last[i]) >> 1);
127
            dst[i] = p + src[i];
128
        }
129
        break;
130
    case PNG_FILTER_VALUE_PAETH:
131
        for(i = 0; i < bpp; i++) {
132
            p = last[i];
133
            dst[i] = p + src[i];
134
        }
135
        for(i = bpp; i < size; i++) {
136
            int a, b, c, pa, pb, pc;
137

    
138
            a = dst[i - bpp];
139
            b = last[i];
140
            c = last[i - bpp];
141

    
142
            p = b - c;
143
            pc = a - c;
144

    
145
            pa = abs(p);
146
            pb = abs(pc);
147
            pc = abs(p + pc);
148

    
149
            if (pa <= pb && pa <= pc)
150
                p = a;
151
            else if (pb <= pc)
152
                p = b;
153
            else
154
                p = c;
155
            dst[i] = p + src[i];
156
        }
157
        break;
158
    }
159
}
160

    
161
static void png_handle_row(PNGDecodeState *s)
162
{
163
    uint8_t *ptr, *last_row;
164

    
165
    ptr = s->image_buf + s->image_linesize * s->y;
166

    
167
    /* need to swap bytes correctly for RGB_ALPHA */
168
    if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
169
        int j, w;
170
        unsigned int r, g, b, a;
171
        const uint8_t *src;
172

    
173
        png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, 
174
                       s->empty_row, s->row_size, s->bpp);
175
        memcpy(s->empty_row, s->tmp_row, s->row_size);
176

    
177
        src = s->tmp_row;
178
        w = s->width;
179
        for(j = 0;j < w; j++) {
180
            r = src[0];
181
            g = src[1];
182
            b = src[2];
183
            a = src[3];
184
            *(uint32_t *)ptr = (a << 24) | (r << 16) | (g << 8) | b;
185
            ptr += 4;
186
            src += 4;
187
        }
188
    } else {
189
        /* in normal case, we avoid one copy */
190

    
191
        if (s->y == 0)
192
            last_row = s->empty_row;
193
        else
194
            last_row = ptr - s->image_linesize;
195
        
196
        png_filter_row(ptr, s->crow_buf[0], s->crow_buf + 1, 
197
                       last_row, s->row_size, s->bpp);
198
    }
199
}
200

    
201
static int png_decode_idat(PNGDecodeState *s, ByteIOContext *f, int length)
202
{
203
    uint8_t buf[IOBUF_SIZE];
204
    int buf_size;
205
    int ret;
206
    while (length > 0) {
207
        /* read the buffer */
208
        buf_size = IOBUF_SIZE;
209
        if (buf_size > length)
210
            buf_size = length;
211
        ret = get_buffer(f, buf, buf_size);
212
        if (ret != buf_size)
213
            return -1;
214
        s->zstream.avail_in = buf_size;
215
        s->zstream.next_in = buf;
216
        /* decode one line if possible */
217
        while (s->zstream.avail_in > 0) {
218
            ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
219
            if (ret != Z_OK && ret != Z_STREAM_END) {
220
                return -1;
221
            }
222
            if (s->zstream.avail_out == 0) {
223
                if (s->y < s->height) {
224
                    png_handle_row(s);
225
                    s->y++;
226
                    if (s->y == s->height)
227
                        s->state |= PNG_ALLIMAGE;
228
                }
229
                s->zstream.avail_out = s->crow_size;
230
                s->zstream.next_out = s->crow_buf;
231
            }
232
        }
233
        length -= buf_size;
234
    }
235
    return 0;
236
}
237

    
238
static int png_read(ByteIOContext *f, 
239
                    int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
240
{
241
    AVImageInfo info1, *info = &info1;
242
    PNGDecodeState s1, *s = &s1;
243
    uint32_t tag, length;
244
    int ret, crc;
245
    uint8_t buf[8];
246

    
247
    /* check signature */
248
    ret = get_buffer(f, buf, 8);
249
    if (ret != 8)
250
        return -1;
251
    if (memcmp(buf, pngsig, 8) != 0)
252
        return -1;
253
    memset(s, 0, sizeof(PNGDecodeState));
254
    /* init the zlib */
255
    s->zstream.zalloc = png_zalloc;
256
    s->zstream.zfree = png_zfree;
257
    s->zstream.opaque = NULL;
258
    ret = inflateInit(&s->zstream);
259
    if (ret != Z_OK)
260
        return -1;
261
    for(;;) {
262
        if (url_feof(f))
263
            goto fail;
264
        length = get_be32(f);
265
        if (length > 0x7fffffff)
266
            goto fail;
267
        tag = get_le32(f);
268
#ifdef DEBUG
269
        printf("png: tag=%c%c%c%c length=%u\n", 
270
               (tag & 0xff),
271
               ((tag >> 8) & 0xff),
272
               ((tag >> 16) & 0xff),
273
               ((tag >> 24) & 0xff), length);
274
#endif
275
        switch(tag) {
276
        case MKTAG('I', 'H', 'D', 'R'):
277
            if (length != 13)
278
                goto fail;
279
            s->width = get_be32(f);
280
            s->height = get_be32(f);
281
            s->bit_depth = get_byte(f);
282
            s->color_type = get_byte(f);
283
            s->compression_type = get_byte(f);
284
            s->filter_type = get_byte(f);
285
            s->interlace_type = get_byte(f);
286
            crc = get_be32(f);
287
            s->state |= PNG_IHDR;
288
#ifdef DEBUG
289
            printf("width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", 
290
                   s->width, s->height, s->bit_depth, s->color_type, 
291
                   s->compression_type, s->filter_type, s->interlace_type);
292
#endif
293
            break;
294
        case MKTAG('I', 'D', 'A', 'T'):
295
            if (!(s->state & PNG_IHDR))
296
                goto fail;
297
            if (!(s->state & PNG_IDAT)) {
298
                /* init image info */
299
                info->width = s->width;
300
                info->height = s->height;
301

    
302
                s->channels = 1;
303
                if ((s->color_type & (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)) ==
304
                    PNG_COLOR_MASK_COLOR)
305
                    s->channels = 3;
306
                if (s->color_type & PNG_COLOR_MASK_ALPHA)
307
                    s->channels++;
308
                s->bits_per_pixel = s->bit_depth * s->channels;
309
                s->bpp = (s->bits_per_pixel + 7) >> 3;
310
                if (s->bit_depth == 8 && 
311
                    s->color_type == PNG_COLOR_TYPE_RGB) {
312
                    info->pix_fmt = PIX_FMT_RGB24;
313
                    s->row_size = s->width * 3;
314
                } else if (s->bit_depth == 8 && 
315
                           s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
316
                    info->pix_fmt = PIX_FMT_RGBA32;
317
                    s->row_size = s->width * 4;
318
                } else if (s->bit_depth == 8 && 
319
                           s->color_type == PNG_COLOR_TYPE_GRAY) {
320
                    info->pix_fmt = PIX_FMT_GRAY8;
321
                    s->row_size = s->width;
322
                } else if (s->bit_depth == 1 && 
323
                           s->color_type == PNG_COLOR_TYPE_GRAY) {
324
                    info->pix_fmt = PIX_FMT_MONOBLACK;
325
                    s->row_size = (s->width + 7) >> 3;
326
                } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
327
                    info->pix_fmt = PIX_FMT_PAL8;
328
                    s->row_size = s->width;
329
                } else {
330
                    goto fail;
331
                }
332
                /* compute the compressed row size */
333
                if (!s->interlace_type) {
334
                    s->crow_size = s->row_size + 1;
335
                } else {
336
                    /* XXX: handle interlacing */
337
                    goto fail;
338
                }
339
                ret = alloc_cb(opaque, info);
340
                if (ret) 
341
                    goto the_end;
342
#ifdef DEBUG
343
                printf("row_size=%d crow_size =%d\n", 
344
                       s->row_size, s->crow_size);
345
#endif
346
                s->image_buf = info->pict.data[0];
347
                s->image_linesize = info->pict.linesize[0];
348
                /* copy the palette if needed */
349
                if (s->color_type == PNG_COLOR_TYPE_PALETTE)
350
                    memcpy(info->pict.data[1], s->palette, 256 * sizeof(uint32_t));
351
                /* empty row is used if differencing to the first row */
352
                s->empty_row = av_mallocz(s->row_size);
353
                if (!s->empty_row)
354
                    goto fail;
355
                if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
356
                    s->tmp_row = av_malloc(s->row_size);
357
                    if (!s->tmp_row)
358
                        goto fail;
359
                }
360
                /* compressed row */
361
                s->crow_buf = av_malloc(s->crow_size);
362
                if (!s->crow_buf)
363
                    goto fail;
364
                s->zstream.avail_out = s->crow_size;
365
                s->zstream.next_out = s->crow_buf;
366
            }
367
            s->state |= PNG_IDAT;
368
            if (png_decode_idat(s, f, length) < 0)
369
                goto fail;
370
            /* skip crc */
371
            crc = get_be32(f);
372
            break;
373
        case MKTAG('P', 'L', 'T', 'E'):
374
            {
375
                int n, i, r, g, b;
376
                
377
                if ((length % 3) != 0 || length > 256 * 3)
378
                    goto skip_tag;
379
                /* read the palette */
380
                n = length / 3;
381
                for(i=0;i<n;i++) {
382
                    r = get_byte(f);
383
                    g = get_byte(f);
384
                    b = get_byte(f);
385
                    s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
386
                }
387
                for(;i<256;i++) {
388
                    s->palette[i] = (0xff << 24);
389
                }
390
                s->state |= PNG_PLTE;
391
                crc = get_be32(f);
392
            }
393
            break;
394
        case MKTAG('t', 'R', 'N', 'S'):
395
            {
396
                int v, i;
397

    
398
                /* read the transparency. XXX: Only palette mode supported */
399
                if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
400
                    length > 256 ||
401
                    !(s->state & PNG_PLTE))
402
                    goto skip_tag;
403
                for(i=0;i<length;i++) {
404
                    v = get_byte(f);
405
                    s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
406
                }
407
                crc = get_be32(f);
408
            }
409
            break;
410
        case MKTAG('I', 'E', 'N', 'D'):
411
            if (!(s->state & PNG_ALLIMAGE))
412
                goto fail;
413
            crc = get_be32(f);
414
            goto exit_loop;
415
        default:
416
            /* skip tag */
417
        skip_tag:
418
            url_fskip(f, length + 4);
419
            break;
420
        }
421
    }
422
 exit_loop:
423
    ret = 0;
424
 the_end:
425
    inflateEnd(&s->zstream);
426
    av_free(s->crow_buf);
427
    av_free(s->empty_row);
428
    av_free(s->tmp_row);
429
    return ret;
430
 fail:
431
    ret = -1;
432
    goto the_end;
433
}
434

    
435
static void png_write_chunk(ByteIOContext *f, uint32_t tag,
436
                            const uint8_t *buf, int length)
437
{
438
    uint32_t crc;
439
    uint8_t tagbuf[4];
440

    
441
    put_be32(f, length);
442
    crc = crc32(0, Z_NULL, 0);
443
    tagbuf[0] = tag;
444
    tagbuf[1] = tag >> 8;
445
    tagbuf[2] = tag >> 16;
446
    tagbuf[3] = tag >> 24;
447
    crc = crc32(crc, tagbuf, 4);
448
    put_le32(f, tag);
449
    if (length > 0) {
450
        crc = crc32(crc, buf, length);
451
        put_buffer(f, buf, length);
452
    }
453
    put_be32(f, crc);
454
}
455

    
456
/* XXX: use avcodec generic function ? */
457
static void to_be32(uint8_t *p, uint32_t v)
458
{
459
    p[0] = v >> 24;
460
    p[1] = v >> 16;
461
    p[2] = v >> 8;
462
    p[3] = v;
463
}
464

    
465
static int png_write(ByteIOContext *f, AVImageInfo *info)
466
{
467
    int bit_depth, color_type, y, len, row_size, ret;
468
    uint8_t *ptr;
469
    uint8_t buf[IOBUF_SIZE];
470
    uint8_t *crow_buf = NULL;
471
    z_stream zstream;
472
    
473
    switch(info->pix_fmt) {
474
    case PIX_FMT_RGBA32:
475
        bit_depth = 8;
476
        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
477
        row_size = info->width * 4;
478
        break;
479
    case PIX_FMT_RGB24:
480
        bit_depth = 8;
481
        color_type = PNG_COLOR_TYPE_RGB;
482
        row_size = info->width * 3;
483
        break;
484
    case PIX_FMT_GRAY8:
485
        bit_depth = 8;
486
        color_type = PNG_COLOR_TYPE_GRAY;
487
        row_size = info->width;
488
        break;
489
    case PIX_FMT_MONOBLACK:
490
        bit_depth = 1;
491
        color_type = PNG_COLOR_TYPE_GRAY;
492
        row_size = (info->width + 7) >> 3;
493
        break;
494
    case PIX_FMT_PAL8:
495
        bit_depth = 8;
496
        color_type = PNG_COLOR_TYPE_PALETTE;
497
        row_size = info->width;
498
        break;
499
    default:
500
        return -1;
501
    }
502
    zstream.zalloc = png_zalloc;
503
    zstream.zfree = png_zfree;
504
    zstream.opaque = NULL;
505
    ret = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION,
506
                       Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY);
507
    if (ret != Z_OK)
508
        return -1;
509
    crow_buf = av_malloc(row_size + 1);
510
    if (!crow_buf)
511
        goto fail;
512

    
513
    /* write png header */
514
    put_buffer(f, pngsig, 8);
515
    
516
    to_be32(buf, info->width);
517
    to_be32(buf + 4, info->height);
518
    buf[8] = bit_depth;
519
    buf[9] = color_type;
520
    buf[10] = 0; /* compression type */
521
    buf[11] = 0; /* filter type */
522
    buf[12] = 0; /* interlace type */
523
    
524
    png_write_chunk(f, MKTAG('I', 'H', 'D', 'R'), buf, 13);
525

    
526
    /* put the palette if needed */
527
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
528
        int has_alpha, alpha, i;
529
        unsigned int v;
530
        uint32_t *palette;
531
        uint8_t *alpha_ptr;
532
        
533
        palette = (uint32_t *)info->pict.data[1];
534
        ptr = buf;
535
        alpha_ptr = buf + 256 * 3;
536
        has_alpha = 0;
537
        for(i = 0; i < 256; i++) {
538
            v = palette[i];
539
            alpha = v >> 24;
540
            if (alpha != 0xff)
541
                has_alpha = 1;
542
            *alpha_ptr++ = alpha;
543
            ptr[0] = v >> 16;
544
            ptr[1] = v >> 8;
545
            ptr[2] = v;
546
            ptr += 3;
547
        }
548
        png_write_chunk(f, MKTAG('P', 'L', 'T', 'E'), buf, 256 * 3);
549
        if (has_alpha) {
550
            png_write_chunk(f, MKTAG('t', 'R', 'N', 'S'), buf + 256 * 3, 256);
551
        }
552
    }
553

    
554
    /* now put each row */
555
    zstream.avail_out = IOBUF_SIZE;
556
    zstream.next_out = buf;
557
    for(y = 0;y < info->height; y++) {
558
        /* XXX: do filtering */
559
        ptr = info->pict.data[0] + y * info->pict.linesize[0];
560
        if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
561
            uint8_t *d;
562
            int j, w;
563
            unsigned int v;
564

    
565
            w = info->width;
566
            d = crow_buf + 1;
567
            for(j = 0; j < w; j++) {
568
                v = ((uint32_t *)ptr)[j];
569
                d[0] = v >> 16;
570
                d[1] = v >> 8;
571
                d[2] = v;
572
                d[3] = v >> 24;
573
                d += 4;
574
            }
575
        } else {
576
            memcpy(crow_buf + 1, ptr, row_size);
577
        }
578
        crow_buf[0] = PNG_FILTER_VALUE_NONE;
579
        zstream.avail_in = row_size + 1;
580
        zstream.next_in = crow_buf;
581
        while (zstream.avail_in > 0) {
582
            ret = deflate(&zstream, Z_NO_FLUSH);
583
            if (ret != Z_OK)
584
                goto fail;
585
            if (zstream.avail_out == 0) {
586
                png_write_chunk(f, MKTAG('I', 'D', 'A', 'T'), buf, IOBUF_SIZE);
587
                zstream.avail_out = IOBUF_SIZE;
588
                zstream.next_out = buf;
589
            }
590
        }
591
    }
592
    /* compress last bytes */
593
    for(;;) {
594
        ret = deflate(&zstream, Z_FINISH);
595
        if (ret == Z_OK || ret == Z_STREAM_END) {
596
            len = IOBUF_SIZE - zstream.avail_out;
597
            if (len > 0) {
598
                png_write_chunk(f, MKTAG('I', 'D', 'A', 'T'), buf, len);
599
            }
600
            zstream.avail_out = IOBUF_SIZE;
601
            zstream.next_out = buf;
602
            if (ret == Z_STREAM_END)
603
                break;
604
        } else {
605
            goto fail;
606
        }
607
    }
608
    png_write_chunk(f, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
609

    
610
    put_flush_packet(f);
611
    ret = 0;
612
 the_end:
613
    av_free(crow_buf);
614
    deflateEnd(&zstream);
615
    return ret;
616
 fail:
617
    ret = -1;
618
    goto the_end;
619
}
620

    
621
AVImageFormat png_image_format = {
622
    "png",
623
    "png",
624
    png_probe,
625
    png_read,
626
    (1 << PIX_FMT_RGBA32) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_GRAY8) | 
627
    (1 << PIX_FMT_MONOBLACK) | (1 << PIX_FMT_PAL8),
628
    png_write,
629
};
630
#endif