Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libwebp/src/dec/alpha_dec.c
21147 views
1
// Copyright 2011 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
// Alpha-plane decompression.
11
//
12
// Author: Skal ([email protected])
13
14
#include <assert.h>
15
#include <stdlib.h>
16
17
#include "src/dec/alphai_dec.h"
18
#include "src/dec/vp8_dec.h"
19
#include "src/dec/vp8i_dec.h"
20
#include "src/dec/vp8li_dec.h"
21
#include "src/dec/webpi_dec.h"
22
#include "src/dsp/dsp.h"
23
#include "src/utils/quant_levels_dec_utils.h"
24
#include "src/utils/utils.h"
25
#include "src/webp/decode.h"
26
#include "src/webp/format_constants.h"
27
#include "src/webp/types.h"
28
29
//------------------------------------------------------------------------------
30
// ALPHDecoder object.
31
32
// Allocates a new alpha decoder instance.
33
WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
34
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
35
return dec;
36
}
37
38
// Clears and deallocates an alpha decoder instance.
39
static void ALPHDelete(ALPHDecoder* const dec) {
40
if (dec != NULL) {
41
VP8LDelete(dec->vp8l_dec);
42
dec->vp8l_dec = NULL;
43
WebPSafeFree(dec);
44
}
45
}
46
47
//------------------------------------------------------------------------------
48
// Decoding.
49
50
// Initialize alpha decoding by parsing the alpha header and decoding the image
51
// header for alpha data stored using lossless compression.
52
// Returns false in case of error in alpha header (data too short, invalid
53
// compression method or filter, error in lossless header data etc).
54
WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
55
size_t data_size, const VP8Io* const src_io,
56
uint8_t* output) {
57
int ok = 0;
58
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
59
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
60
int rsrv;
61
VP8Io* const io = &dec->io;
62
63
assert(data != NULL && output != NULL && src_io != NULL);
64
65
VP8FiltersInit();
66
dec->output = output;
67
dec->width = src_io->width;
68
dec->height = src_io->height;
69
assert(dec->width > 0 && dec->height > 0);
70
71
if (data_size <= ALPHA_HEADER_LEN) {
72
return 0;
73
}
74
75
dec->method = (data[0] >> 0) & 0x03;
76
dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
77
dec->pre_processing = (data[0] >> 4) & 0x03;
78
rsrv = (data[0] >> 6) & 0x03;
79
if (dec->method < ALPHA_NO_COMPRESSION ||
80
dec->method > ALPHA_LOSSLESS_COMPRESSION ||
81
dec->filter >= WEBP_FILTER_LAST ||
82
dec->pre_processing > ALPHA_PREPROCESSED_LEVELS ||
83
rsrv != 0) {
84
return 0;
85
}
86
87
// Copy the necessary parameters from src_io to io
88
if (!VP8InitIo(io)) {
89
return 0;
90
}
91
WebPInitCustomIo(NULL, io);
92
io->opaque = dec;
93
io->width = src_io->width;
94
io->height = src_io->height;
95
96
io->use_cropping = src_io->use_cropping;
97
io->crop_left = src_io->crop_left;
98
io->crop_right = src_io->crop_right;
99
io->crop_top = src_io->crop_top;
100
io->crop_bottom = src_io->crop_bottom;
101
// No need to copy the scaling parameters.
102
103
if (dec->method == ALPHA_NO_COMPRESSION) {
104
const size_t alpha_decoded_size = dec->width * dec->height;
105
ok = (alpha_data_size >= alpha_decoded_size);
106
} else {
107
assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);
108
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
109
}
110
111
return ok;
112
}
113
114
// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
115
// starting from row number 'row'. It assumes that rows up to (row - 1) have
116
// already been decoded.
117
// Returns false in case of bitstream error.
118
WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
119
int num_rows) {
120
ALPHDecoder* const alph_dec = dec->alph_dec;
121
const int width = alph_dec->width;
122
const int height = alph_dec->io.crop_bottom;
123
if (alph_dec->method == ALPHA_NO_COMPRESSION) {
124
int y;
125
const uint8_t* prev_line = dec->alpha_prev_line;
126
const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width;
127
uint8_t* dst = dec->alpha_plane + row * width;
128
assert(deltas <= &dec->alpha_data[dec->alpha_data_size]);
129
assert(WebPUnfilters[alph_dec->filter] != NULL);
130
for (y = 0; y < num_rows; ++y) {
131
WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width);
132
prev_line = dst;
133
dst += width;
134
deltas += width;
135
}
136
dec->alpha_prev_line = prev_line;
137
} else { // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION
138
assert(alph_dec->vp8l_dec != NULL);
139
if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
140
return 0;
141
}
142
}
143
144
if (row + num_rows >= height) {
145
dec->is_alpha_decoded = 1;
146
}
147
return 1;
148
}
149
150
WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
151
const VP8Io* const io) {
152
const int stride = io->width;
153
const int height = io->crop_bottom;
154
const uint64_t alpha_size = (uint64_t)stride * height;
155
assert(dec->alpha_plane_mem == NULL);
156
dec->alpha_plane_mem =
157
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane));
158
if (dec->alpha_plane_mem == NULL) {
159
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
160
"Alpha decoder initialization failed.");
161
}
162
dec->alpha_plane = dec->alpha_plane_mem;
163
dec->alpha_prev_line = NULL;
164
return 1;
165
}
166
167
void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
168
assert(dec != NULL);
169
WebPSafeFree(dec->alpha_plane_mem);
170
dec->alpha_plane_mem = NULL;
171
dec->alpha_plane = NULL;
172
ALPHDelete(dec->alph_dec);
173
dec->alph_dec = NULL;
174
}
175
176
//------------------------------------------------------------------------------
177
// Main entry point.
178
179
WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
180
const VP8Io* const io,
181
int row, int num_rows) {
182
const int width = io->width;
183
const int height = io->crop_bottom;
184
185
assert(dec != NULL && io != NULL);
186
187
if (row < 0 || num_rows <= 0 || row + num_rows > height) {
188
return NULL;
189
}
190
191
if (!dec->is_alpha_decoded) {
192
if (dec->alph_dec == NULL) { // Initialize decoder.
193
dec->alph_dec = ALPHNew();
194
if (dec->alph_dec == NULL) {
195
VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
196
"Alpha decoder initialization failed.");
197
return NULL;
198
}
199
if (!AllocateAlphaPlane(dec, io)) goto Error;
200
if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size,
201
io, dec->alpha_plane)) {
202
VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec;
203
VP8SetError(dec,
204
(vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY
205
: vp8l_dec->status,
206
"Alpha decoder initialization failed.");
207
goto Error;
208
}
209
// if we allowed use of alpha dithering, check whether it's needed at all
210
if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) {
211
dec->alpha_dithering = 0; // disable dithering
212
} else {
213
num_rows = height - row; // decode everything in one pass
214
}
215
}
216
217
assert(dec->alph_dec != NULL);
218
assert(row + num_rows <= height);
219
if (!ALPHDecode(dec, row, num_rows)) goto Error;
220
221
if (dec->is_alpha_decoded) { // finished?
222
ALPHDelete(dec->alph_dec);
223
dec->alph_dec = NULL;
224
if (dec->alpha_dithering > 0) {
225
uint8_t* const alpha = dec->alpha_plane + io->crop_top * width
226
+ io->crop_left;
227
if (!WebPDequantizeLevels(alpha,
228
io->crop_right - io->crop_left,
229
io->crop_bottom - io->crop_top,
230
width, dec->alpha_dithering)) {
231
goto Error;
232
}
233
}
234
}
235
}
236
237
// Return a pointer to the current decoded row.
238
return dec->alpha_plane + row * width;
239
240
Error:
241
WebPDeallocateAlphaMemory(dec);
242
return NULL;
243
}
244
245