1 // Copyright 2014 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 // WebPPicture tools: alpha handling, etc.
12 // Author: Skal (pascal.massimino@gmail.com)
14 #include "./vp8enci.h"
15 #include "../dsp/yuv.h"
17 static WEBP_INLINE
uint32_t MakeARGB32(int r
, int g
, int b
) {
18 return (0xff000000u
| (r
<< 16) | (g
<< 8) | b
);
21 //------------------------------------------------------------------------------
22 // Helper: clean up fully transparent area to help compressibility.
25 #define SIZE2 (SIZE / 2)
26 static int is_transparent_area(const uint8_t* ptr
, int stride
, int size
) {
28 for (y
= 0; y
< size
; ++y
) {
29 for (x
= 0; x
< size
; ++x
) {
39 static int is_transparent_argb_area(const uint32_t* ptr
, int stride
, int size
) {
41 for (y
= 0; y
< size
; ++y
) {
42 for (x
= 0; x
< size
; ++x
) {
43 if (ptr
[x
] & 0xff000000u
) {
52 static void flatten(uint8_t* ptr
, int v
, int stride
, int size
) {
54 for (y
= 0; y
< size
; ++y
) {
60 static void flatten_argb(uint32_t* ptr
, uint32_t v
, int stride
, int size
) {
62 for (y
= 0; y
< size
; ++y
) {
63 for (x
= 0; x
< size
; ++x
) ptr
[x
] = v
;
68 void WebPCleanupTransparentArea(WebPPicture
* pic
) {
70 if (pic
== NULL
) return;
71 w
= pic
->width
/ SIZE
;
72 h
= pic
->height
/ SIZE
;
74 // note: we ignore the left-overs on right/bottom
76 uint32_t argb_value
= 0;
77 for (y
= 0; y
< h
; ++y
) {
79 for (x
= 0; x
< w
; ++x
) {
80 const int off
= (y
* pic
->argb_stride
+ x
) * SIZE
;
81 if (is_transparent_argb_area(pic
->argb
+ off
, pic
->argb_stride
, SIZE
)) {
83 argb_value
= pic
->argb
[off
];
86 flatten_argb(pic
->argb
+ off
, argb_value
, pic
->argb_stride
, SIZE
);
93 const uint8_t* const a_ptr
= pic
->a
;
94 int values
[3] = { 0 };
95 if (a_ptr
== NULL
) return; // nothing to do
96 for (y
= 0; y
< h
; ++y
) {
98 for (x
= 0; x
< w
; ++x
) {
99 const int off_a
= (y
* pic
->a_stride
+ x
) * SIZE
;
100 const int off_y
= (y
* pic
->y_stride
+ x
) * SIZE
;
101 const int off_uv
= (y
* pic
->uv_stride
+ x
) * SIZE2
;
102 if (is_transparent_area(a_ptr
+ off_a
, pic
->a_stride
, SIZE
)) {
104 values
[0] = pic
->y
[off_y
];
105 values
[1] = pic
->u
[off_uv
];
106 values
[2] = pic
->v
[off_uv
];
109 flatten(pic
->y
+ off_y
, values
[0], pic
->y_stride
, SIZE
);
110 flatten(pic
->u
+ off_uv
, values
[1], pic
->uv_stride
, SIZE2
);
111 flatten(pic
->v
+ off_uv
, values
[2], pic
->uv_stride
, SIZE2
);
123 //------------------------------------------------------------------------------
124 // Blend color and remove transparency info
126 #define BLEND(V0, V1, ALPHA) \
127 ((((V0) * (255 - (ALPHA)) + (V1) * (ALPHA)) * 0x101) >> 16)
128 #define BLEND_10BIT(V0, V1, ALPHA) \
129 ((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101) >> 18)
131 void WebPBlendAlpha(WebPPicture
* pic
, uint32_t background_rgb
) {
132 const int red
= (background_rgb
>> 16) & 0xff;
133 const int green
= (background_rgb
>> 8) & 0xff;
134 const int blue
= (background_rgb
>> 0) & 0xff;
136 if (pic
== NULL
) return;
137 if (!pic
->use_argb
) {
138 const int uv_width
= (pic
->width
>> 1); // omit last pixel during u/v loop
139 const int Y0
= VP8RGBToY(red
, green
, blue
, YUV_HALF
);
140 // VP8RGBToU/V expects the u/v values summed over four pixels
141 const int U0
= VP8RGBToU(4 * red
, 4 * green
, 4 * blue
, 4 * YUV_HALF
);
142 const int V0
= VP8RGBToV(4 * red
, 4 * green
, 4 * blue
, 4 * YUV_HALF
);
143 const int has_alpha
= pic
->colorspace
& WEBP_CSP_ALPHA_BIT
;
144 if (!has_alpha
|| pic
->a
== NULL
) return; // nothing to do
145 for (y
= 0; y
< pic
->height
; ++y
) {
147 uint8_t* const y_ptr
= pic
->y
+ y
* pic
->y_stride
;
148 uint8_t* const a_ptr
= pic
->a
+ y
* pic
->a_stride
;
149 for (x
= 0; x
< pic
->width
; ++x
) {
150 const int alpha
= a_ptr
[x
];
152 y_ptr
[x
] = BLEND(Y0
, y_ptr
[x
], a_ptr
[x
]);
155 // Chroma blending every even line
157 uint8_t* const u
= pic
->u
+ (y
>> 1) * pic
->uv_stride
;
158 uint8_t* const v
= pic
->v
+ (y
>> 1) * pic
->uv_stride
;
159 uint8_t* const a_ptr2
=
160 (y
+ 1 == pic
->height
) ? a_ptr
: a_ptr
+ pic
->a_stride
;
161 for (x
= 0; x
< uv_width
; ++x
) {
162 // Average four alpha values into a single blending weight.
163 // TODO(skal): might lead to visible contouring. Can we do better?
165 a_ptr
[2 * x
+ 0] + a_ptr
[2 * x
+ 1] +
166 a_ptr2
[2 * x
+ 0] + a_ptr2
[2 * x
+ 1];
167 u
[x
] = BLEND_10BIT(U0
, u
[x
], alpha
);
168 v
[x
] = BLEND_10BIT(V0
, v
[x
], alpha
);
170 if (pic
->width
& 1) { // rightmost pixel
171 const int alpha
= 2 * (a_ptr
[2 * x
+ 0] + a_ptr2
[2 * x
+ 0]);
172 u
[x
] = BLEND_10BIT(U0
, u
[x
], alpha
);
173 v
[x
] = BLEND_10BIT(V0
, v
[x
], alpha
);
176 memset(a_ptr
, 0xff, pic
->width
);
179 uint32_t* argb
= pic
->argb
;
180 const uint32_t background
= MakeARGB32(red
, green
, blue
);
181 for (y
= 0; y
< pic
->height
; ++y
) {
182 for (x
= 0; x
< pic
->width
; ++x
) {
183 const int alpha
= (argb
[x
] >> 24) & 0xff;
186 int r
= (argb
[x
] >> 16) & 0xff;
187 int g
= (argb
[x
] >> 8) & 0xff;
188 int b
= (argb
[x
] >> 0) & 0xff;
189 r
= BLEND(red
, r
, alpha
);
190 g
= BLEND(green
, g
, alpha
);
191 b
= BLEND(blue
, b
, alpha
);
192 argb
[x
] = MakeARGB32(r
, g
, b
);
194 argb
[x
] = background
;
198 argb
+= pic
->argb_stride
;
206 //------------------------------------------------------------------------------