Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}