Coverage Report

Created: 2026-06-30 07:12

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