1 // Copyright 2011 Google Inc. All Rights Reserved.
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 // -----------------------------------------------------------------------------
10 // Alpha-plane decompression.
12 // Author: Skal (pascal.massimino@gmail.com)
18 #include "../utils/quant_levels_dec.h"
19 #include "../utils/utils.h"
20 #include "../webp/format_constants.h"
22 //------------------------------------------------------------------------------
23 // ALPHDecoder object.
25 ALPHDecoder
* ALPHNew(void) {
26 ALPHDecoder
* const dec
= (ALPHDecoder
*)WebPSafeCalloc(1ULL, sizeof(*dec
));
30 void ALPHDelete(ALPHDecoder
* const dec
) {
32 VP8LDelete(dec
->vp8l_dec_
);
33 dec
->vp8l_dec_
= NULL
;
38 //------------------------------------------------------------------------------
41 // Initialize alpha decoding by parsing the alpha header and decoding the image
42 // header for alpha data stored using lossless compression.
43 // Returns false in case of error in alpha header (data too short, invalid
44 // compression method or filter, error in lossless header data etc).
45 static int ALPHInit(ALPHDecoder
* const dec
, const uint8_t* data
,
46 size_t data_size
, int width
, int height
, uint8_t* output
) {
48 const uint8_t* const alpha_data
= data
+ ALPHA_HEADER_LEN
;
49 const size_t alpha_data_size
= data_size
- ALPHA_HEADER_LEN
;
52 assert(width
> 0 && height
> 0);
53 assert(data
!= NULL
&& output
!= NULL
);
56 dec
->height_
= height
;
58 if (data_size
<= ALPHA_HEADER_LEN
) {
62 dec
->method_
= (data
[0] >> 0) & 0x03;
63 dec
->filter_
= (data
[0] >> 2) & 0x03;
64 dec
->pre_processing_
= (data
[0] >> 4) & 0x03;
65 rsrv
= (data
[0] >> 6) & 0x03;
66 if (dec
->method_
< ALPHA_NO_COMPRESSION
||
67 dec
->method_
> ALPHA_LOSSLESS_COMPRESSION
||
68 dec
->filter_
>= WEBP_FILTER_LAST
||
69 dec
->pre_processing_
> ALPHA_PREPROCESSED_LEVELS
||
74 if (dec
->method_
== ALPHA_NO_COMPRESSION
) {
75 const size_t alpha_decoded_size
= dec
->width_
* dec
->height_
;
76 ok
= (alpha_data_size
>= alpha_decoded_size
);
78 assert(dec
->method_
== ALPHA_LOSSLESS_COMPRESSION
);
79 ok
= VP8LDecodeAlphaHeader(dec
, alpha_data
, alpha_data_size
, output
);
84 // Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
85 // starting from row number 'row'. It assumes that rows up to (row - 1) have
86 // already been decoded.
87 // Returns false in case of bitstream error.
88 static int ALPHDecode(VP8Decoder
* const dec
, int row
, int num_rows
) {
89 ALPHDecoder
* const alph_dec
= dec
->alph_dec_
;
90 const int width
= alph_dec
->width_
;
91 const int height
= alph_dec
->height_
;
92 WebPUnfilterFunc unfilter_func
= WebPUnfilters
[alph_dec
->filter_
];
93 uint8_t* const output
= dec
->alpha_plane_
;
94 if (alph_dec
->method_
== ALPHA_NO_COMPRESSION
) {
95 const size_t offset
= row
* width
;
96 const size_t num_pixels
= num_rows
* width
;
97 assert(dec
->alpha_data_size_
>= ALPHA_HEADER_LEN
+ offset
+ num_pixels
);
98 memcpy(dec
->alpha_plane_
+ offset
,
99 dec
->alpha_data_
+ ALPHA_HEADER_LEN
+ offset
, num_pixels
);
100 } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
101 assert(alph_dec
->vp8l_dec_
!= NULL
);
102 if (!VP8LDecodeAlphaImageStream(alph_dec
, row
+ num_rows
)) {
107 if (unfilter_func
!= NULL
) {
108 unfilter_func(width
, height
, width
, row
, num_rows
, output
);
111 if (row
+ num_rows
== dec
->pic_hdr_
.height_
) {
112 dec
->is_alpha_decoded_
= 1;
117 //------------------------------------------------------------------------------
120 const uint8_t* VP8DecompressAlphaRows(VP8Decoder
* const dec
,
121 int row
, int num_rows
) {
122 const int width
= dec
->pic_hdr_
.width_
;
123 const int height
= dec
->pic_hdr_
.height_
;
125 if (row
< 0 || num_rows
<= 0 || row
+ num_rows
> height
) {
126 return NULL
; // sanity check.
130 // Initialize decoding.
131 assert(dec
->alpha_plane_
!= NULL
);
132 dec
->alph_dec_
= ALPHNew();
133 if (dec
->alph_dec_
== NULL
) return NULL
;
134 if (!ALPHInit(dec
->alph_dec_
, dec
->alpha_data_
, dec
->alpha_data_size_
,
135 width
, height
, dec
->alpha_plane_
)) {
136 ALPHDelete(dec
->alph_dec_
);
137 dec
->alph_dec_
= NULL
;
140 // if we allowed use of alpha dithering, check whether it's needed at all
141 if (dec
->alph_dec_
->pre_processing_
!= ALPHA_PREPROCESSED_LEVELS
) {
142 dec
->alpha_dithering_
= 0; // disable dithering
144 num_rows
= height
; // decode everything in one pass
148 if (!dec
->is_alpha_decoded_
) {
150 assert(dec
->alph_dec_
!= NULL
);
151 ok
= ALPHDecode(dec
, row
, num_rows
);
152 if (ok
&& dec
->alpha_dithering_
> 0) {
153 ok
= WebPDequantizeLevels(dec
->alpha_plane_
, width
, height
,
154 dec
->alpha_dithering_
);
156 if (!ok
|| dec
->is_alpha_decoded_
) {
157 ALPHDelete(dec
->alph_dec_
);
158 dec
->alph_dec_
= NULL
;
160 if (!ok
) return NULL
; // Error.
163 // Return a pointer to the current decoded row.
164 return dec
->alpha_plane_
+ row
* width
;