added 8 bit palette support
authorFabrice Bellard <fabrice@bellard.org>
Sun, 9 Feb 2003 16:22:06 +0000 (16:22 +0000)
committerFabrice Bellard <fabrice@bellard.org>
Sun, 9 Feb 2003 16:22:06 +0000 (16:22 +0000)
Originally committed as revision 1561 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/png.c

index a41c991..e4facf8 100644 (file)
@@ -41,6 +41,7 @@
 #define PNG_IHDR      0x0001
 #define PNG_IDAT      0x0002
 #define PNG_ALLIMAGE  0x0004
+#define PNG_PLTE      0x0008
 
 #define IOBUF_SIZE 4096
 
@@ -58,6 +59,7 @@ typedef struct PNGDecodeState {
     
     uint8_t *image_buf;
     int image_linesize;
+    uint32_t palette[256];
     uint8_t *crow_buf;
     uint8_t *empty_row;
     int crow_size; /* compressed row size (include filter type) */
@@ -66,7 +68,7 @@ typedef struct PNGDecodeState {
     z_stream zstream;
 } PNGDecodeState;
 
-const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+static const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
 
 static int png_probe(AVProbeData *pd)
 {
@@ -77,12 +79,12 @@ static int png_probe(AVProbeData *pd)
         return 0;
 }
 
-void *png_zalloc(void *opaque, unsigned int items, unsigned int size)
+static void *png_zalloc(void *opaque, unsigned int items, unsigned int size)
 {
     return av_malloc(items * size);
 }
 
-void png_zfree(void *opaque, void *ptr)
+static void png_zfree(void *opaque, void *ptr)
 {
     av_free(ptr);
 }
@@ -287,6 +289,9 @@ static int png_read(ByteIOContext *f,
                            s->color_type == PNG_COLOR_TYPE_GRAY) {
                     info->pix_fmt = PIX_FMT_MONOBLACK;
                     s->row_size = (s->width + 7) >> 3;
+                } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
+                    info->pix_fmt = PIX_FMT_PAL8;
+                    s->row_size = s->width;;
                 } else {
                     goto fail;
                 }
@@ -306,6 +311,9 @@ static int png_read(ByteIOContext *f,
 #endif
                 s->image_buf = info->pict.data[0];
                 s->image_linesize = info->pict.linesize[0];
+                /* copy the palette if needed */
+                if (s->color_type == PNG_COLOR_TYPE_PALETTE)
+                    memcpy(info->pict.data[1], s->palette, 256 * sizeof(uint32_t));
                 /* empty row is used if differencing to the first row */
                 s->empty_row = av_mallocz(s->row_size);
                 if (!s->empty_row)
@@ -323,6 +331,43 @@ static int png_read(ByteIOContext *f,
             /* skip crc */
             crc = get_be32(f);
             break;
+        case MKTAG('P', 'L', 'T', 'E'):
+            {
+                int n, i, r, g, b;
+                
+                if ((length % 3) != 0 || length > 256 * 3)
+                    goto skip_tag;
+                /* read the palette */
+                n = length / 3;
+                for(i=0;i<n;i++) {
+                    r = get_byte(f);
+                    g = get_byte(f);
+                    b = get_byte(f);
+                    s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
+                }
+                for(;i<256;i++) {
+                    s->palette[i] = (0xff << 24);
+                }
+                s->state |= PNG_PLTE;
+                crc = get_be32(f);
+            }
+            break;
+        case MKTAG('t', 'R', 'N', 'S'):
+            {
+                int v, i;
+
+                /* read the transparency. XXX: Only palette mode supported */
+                if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
+                    length > 256 ||
+                    !(s->state & PNG_PLTE))
+                    goto skip_tag;
+                for(i=0;i<length;i++) {
+                    v = get_byte(f);
+                    s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
+                }
+                crc = get_be32(f);
+            }
+            break;
         case MKTAG('I', 'E', 'N', 'D'):
             if (!(s->state & PNG_ALLIMAGE))
                 goto fail;
@@ -330,6 +375,7 @@ static int png_read(ByteIOContext *f,
             goto exit_loop;
         default:
             /* skip tag */
+        skip_tag:
             url_fskip(f, length + 4);
             break;
         }
@@ -399,6 +445,11 @@ static int png_write(ByteIOContext *f, AVImageInfo *info)
         color_type = PNG_COLOR_TYPE_GRAY;
         row_size = (info->width + 7) >> 3;
         break;
+    case PIX_FMT_PAL8:
+        bit_depth = 8;
+        color_type = PNG_COLOR_TYPE_PALETTE;
+        row_size = info->width;
+        break;
     default:
         return -1;
     }
@@ -426,6 +477,34 @@ static int png_write(ByteIOContext *f, AVImageInfo *info)
     
     png_write_chunk(f, MKTAG('I', 'H', 'D', 'R'), buf, 13);
 
+    /* put the palette if needed */
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        int has_alpha, alpha, i;
+        unsigned int v;
+        uint32_t *palette;
+        uint8_t *alpha_ptr;
+        
+        palette = (uint32_t *)info->pict.data[1];
+        ptr = buf;
+        alpha_ptr = buf + 256 * 3;
+        has_alpha = 0;
+        for(i = 0; i < 256; i++) {
+            v = palette[i];
+            alpha = v >> 24;
+            if (alpha != 0xff)
+                has_alpha = 1;
+            *alpha_ptr++ = alpha;
+            ptr[0] = v >> 16;
+            ptr[1] = v >> 8;
+            ptr[2] = v;
+            ptr += 3;
+        }
+        png_write_chunk(f, MKTAG('P', 'L', 'T', 'E'), buf, 256 * 3);
+        if (has_alpha) {
+            png_write_chunk(f, MKTAG('t', 'R', 'N', 'S'), buf + 256 * 3, 256);
+        }
+    }
+
     /* now put each row */
     zstream.avail_out = IOBUF_SIZE;
     zstream.next_out = buf;
@@ -481,6 +560,6 @@ AVImageFormat png_image_format = {
     "png",
     png_probe,
     png_read,
-    (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_MONOBLACK),
+    (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_MONOBLACK) | (1 << PIX_FMT_PAL8),
     png_write,
 };