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