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