xref: /aosp_15_r20/external/webp/imageio/webpdec.c (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
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