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