go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

webpdec.c (8024B)


      1 // Copyright 2014 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // WebP decode.
     11 
     12 #ifdef HAVE_CONFIG_H
     13 #include "webp/config.h"
     14 #endif
     15 
     16 #include <assert.h>
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 
     20 #include "../examples/unicode.h"
     21 #include "./imageio_util.h"
     22 #include "./metadata.h"
     23 #include "./webpdec.h"
     24 #include "webp/decode.h"
     25 #include "webp/demux.h"
     26 #include "webp/encode.h"
     27 #include "webp/mux_types.h"
     28 #include "webp/types.h"
     29 
     30 //------------------------------------------------------------------------------
     31 // WebP decoding
     32 
     33 static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
     34   "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
     35   "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
     36 };
     37 
     38 static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
     39   if (config->input.has_animation) {
     40     fprintf(stderr,
     41             "Error! Decoding of an animated WebP file is not supported.\n"
     42             "       Use webpmux to extract the individual frames or\n"
     43             "       vwebp to view this image.\n");
     44   }
     45 }
     46 
     47 void PrintWebPError(const char* const in_file, int status) {
     48   WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file);
     49   fprintf(stderr, "Status: %d", status);
     50   if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
     51     fprintf(stderr, "(%s)", kStatusMessages[status]);
     52   }
     53   fprintf(stderr, "\n");
     54 }
     55 
     56 int LoadWebP(const char* const in_file,
     57              const uint8_t** data, size_t* data_size,
     58              WebPBitstreamFeatures* bitstream) {
     59   VP8StatusCode status;
     60   WebPBitstreamFeatures local_features;
     61   if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0;
     62 
     63   if (bitstream == NULL) {
     64     bitstream = &local_features;
     65   }
     66 
     67   status = WebPGetFeatures(*data, *data_size, bitstream);
     68   if (status != VP8_STATUS_OK) {
     69     WebPFree((void*)*data);
     70     *data = NULL;
     71     *data_size = 0;
     72     PrintWebPError(in_file, status);
     73     return 0;
     74   }
     75   return 1;
     76 }
     77 
     78 //------------------------------------------------------------------------------
     79 
     80 VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
     81                          WebPDecoderConfig* const config) {
     82   if (config == NULL) return VP8_STATUS_INVALID_PARAM;
     83   PrintAnimationWarning(config);
     84   return WebPDecode(data, data_size, config);
     85 }
     86 
     87 VP8StatusCode DecodeWebPIncremental(
     88     const uint8_t* const data, size_t data_size,
     89     WebPDecoderConfig* const config) {
     90   VP8StatusCode status = VP8_STATUS_OK;
     91   if (config == NULL) return VP8_STATUS_INVALID_PARAM;
     92 
     93   PrintAnimationWarning(config);
     94 
     95   // Decoding call.
     96   {
     97     WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
     98     if (idec == NULL) {
     99       fprintf(stderr, "Failed during WebPIDecode().\n");
    100       return VP8_STATUS_OUT_OF_MEMORY;
    101     } else {
    102       status = WebPIUpdate(idec, data, data_size);
    103       WebPIDelete(idec);
    104     }
    105   }
    106   return status;
    107 }
    108 
    109 // -----------------------------------------------------------------------------
    110 // Metadata
    111 
    112 static int ExtractMetadata(const uint8_t* const data, size_t data_size,
    113                            Metadata* const metadata) {
    114   WebPData webp_data = { data, data_size };
    115   WebPDemuxer* const demux = WebPDemux(&webp_data);
    116   WebPChunkIterator chunk_iter;
    117   uint32_t flags;
    118 
    119   if (demux == NULL) return 0;
    120   assert(metadata != NULL);
    121 
    122   flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
    123 
    124   if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
    125     MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
    126                  &metadata->iccp);
    127     WebPDemuxReleaseChunkIterator(&chunk_iter);
    128   }
    129   if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
    130     MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
    131                  &metadata->exif);
    132     WebPDemuxReleaseChunkIterator(&chunk_iter);
    133   }
    134   if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
    135     MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
    136                  &metadata->xmp);
    137     WebPDemuxReleaseChunkIterator(&chunk_iter);
    138   }
    139   WebPDemuxDelete(demux);
    140   return 1;
    141 }
    142 
    143 // -----------------------------------------------------------------------------
    144 
    145 int ReadWebP(const uint8_t* const data, size_t data_size,
    146              WebPPicture* const pic,
    147              int keep_alpha, Metadata* const metadata) {
    148   int ok = 0;
    149   VP8StatusCode status = VP8_STATUS_OK;
    150   WebPDecoderConfig config;
    151   WebPDecBuffer* const output_buffer = &config.output;
    152   WebPBitstreamFeatures* const bitstream = &config.input;
    153 
    154   if (data == NULL || data_size == 0 || pic == NULL) return 0;
    155 
    156   if (!WebPInitDecoderConfig(&config)) {
    157     fprintf(stderr, "Library version mismatch!\n");
    158     return 0;
    159   }
    160 
    161   status = WebPGetFeatures(data, data_size, bitstream);
    162   if (status != VP8_STATUS_OK) {
    163     PrintWebPError("input data", status);
    164     return 0;
    165   }
    166 
    167   do {
    168     const int has_alpha = keep_alpha && bitstream->has_alpha;
    169     uint64_t stride;
    170     pic->width = bitstream->width;
    171     pic->height = bitstream->height;
    172     if (pic->use_argb) {
    173       stride = (uint64_t)bitstream->width * 4;
    174     } else {
    175       stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
    176       pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
    177     }
    178 
    179     if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
    180       status = VP8_STATUS_OUT_OF_MEMORY;
    181       break;
    182     }
    183 
    184     ok = WebPPictureAlloc(pic);
    185     if (!ok) {
    186       status = VP8_STATUS_OUT_OF_MEMORY;
    187       break;
    188     }
    189     if (pic->use_argb) {
    190 #ifdef WORDS_BIGENDIAN
    191       output_buffer->colorspace = MODE_ARGB;
    192 #else
    193       output_buffer->colorspace = MODE_BGRA;
    194 #endif
    195       output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
    196       output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
    197       output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height;
    198     } else {
    199       output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
    200       output_buffer->u.YUVA.y = pic->y;
    201       output_buffer->u.YUVA.u = pic->u;
    202       output_buffer->u.YUVA.v = pic->v;
    203       output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL;
    204       output_buffer->u.YUVA.y_stride = pic->y_stride;
    205       output_buffer->u.YUVA.u_stride = pic->uv_stride;
    206       output_buffer->u.YUVA.v_stride = pic->uv_stride;
    207       output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0;
    208       output_buffer->u.YUVA.y_size = pic->height * pic->y_stride;
    209       output_buffer->u.YUVA.u_size = (pic->height + 1) / 2 * pic->uv_stride;
    210       output_buffer->u.YUVA.v_size = (pic->height + 1) / 2 * pic->uv_stride;
    211       output_buffer->u.YUVA.a_size = pic->height * pic->a_stride;
    212     }
    213     output_buffer->is_external_memory = 1;
    214 
    215     status = DecodeWebP(data, data_size, &config);
    216     ok = (status == VP8_STATUS_OK);
    217     if (ok && !keep_alpha && pic->use_argb) {
    218       // Need to wipe out the alpha value, as requested.
    219       int x, y;
    220       uint32_t* argb = pic->argb;
    221       for (y = 0; y < pic->height; ++y) {
    222         for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u;
    223         argb += pic->argb_stride;
    224       }
    225     }
    226   } while (0);   // <- so we can 'break' out of the loop
    227 
    228   if (status != VP8_STATUS_OK) {
    229     PrintWebPError("input data", status);
    230     ok = 0;
    231   }
    232 
    233   WebPFreeDecBuffer(output_buffer);
    234 
    235   if (ok && metadata != NULL) {
    236     ok = ExtractMetadata(data, data_size, metadata);
    237     if (!ok) {
    238       PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
    239     }
    240   }
    241   if (!ok) WebPPictureFree(pic);
    242   return ok;
    243 }
    244 
    245 // -----------------------------------------------------------------------------