mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
Merge "anim_decode: fix alpha blending with big-endian" into main
This commit is contained in:
commit
ec497b7532
@ -23,6 +23,14 @@
|
|||||||
|
|
||||||
#define NUM_CHANNELS 4
|
#define NUM_CHANNELS 4
|
||||||
|
|
||||||
|
// Channel extraction from a uint32_t representation of a uint8_t RGBA/BGRA
|
||||||
|
// buffer.
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
#define CHANNEL_SHIFT(i) (24 - (i) * 8)
|
||||||
|
#else
|
||||||
|
#define CHANNEL_SHIFT(i) ((i) * 8)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
|
typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
|
||||||
static void BlendPixelRowNonPremult(uint32_t* const src,
|
static void BlendPixelRowNonPremult(uint32_t* const src,
|
||||||
const uint32_t* const dst, int num_pixels);
|
const uint32_t* const dst, int num_pixels);
|
||||||
@ -209,35 +217,35 @@ static uint8_t BlendChannelNonPremult(uint32_t src, uint8_t src_a,
|
|||||||
const uint8_t dst_channel = (dst >> shift) & 0xff;
|
const uint8_t dst_channel = (dst >> shift) & 0xff;
|
||||||
const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
|
const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
|
||||||
assert(blend_unscaled < (1ULL << 32) / scale);
|
assert(blend_unscaled < (1ULL << 32) / scale);
|
||||||
return (blend_unscaled * scale) >> 24;
|
return (blend_unscaled * scale) >> CHANNEL_SHIFT(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
|
// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
|
||||||
static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
|
static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
|
||||||
const uint8_t src_a = (src >> 24) & 0xff;
|
const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
|
|
||||||
if (src_a == 0) {
|
if (src_a == 0) {
|
||||||
return dst;
|
return dst;
|
||||||
} else {
|
} else {
|
||||||
const uint8_t dst_a = (dst >> 24) & 0xff;
|
const uint8_t dst_a = (dst >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
// This is the approximate integer arithmetic for the actual formula:
|
// This is the approximate integer arithmetic for the actual formula:
|
||||||
// dst_factor_a = (dst_a * (255 - src_a)) / 255.
|
// dst_factor_a = (dst_a * (255 - src_a)) / 255.
|
||||||
const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
|
const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
|
||||||
const uint8_t blend_a = src_a + dst_factor_a;
|
const uint8_t blend_a = src_a + dst_factor_a;
|
||||||
const uint32_t scale = (1UL << 24) / blend_a;
|
const uint32_t scale = (1UL << 24) / blend_a;
|
||||||
|
|
||||||
const uint8_t blend_r =
|
const uint8_t blend_r = BlendChannelNonPremult(
|
||||||
BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 0);
|
src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(0));
|
||||||
const uint8_t blend_g =
|
const uint8_t blend_g = BlendChannelNonPremult(
|
||||||
BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 8);
|
src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(1));
|
||||||
const uint8_t blend_b =
|
const uint8_t blend_b = BlendChannelNonPremult(
|
||||||
BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 16);
|
src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(2));
|
||||||
assert(src_a + dst_factor_a < 256);
|
assert(src_a + dst_factor_a < 256);
|
||||||
|
|
||||||
return (blend_r << 0) |
|
return ((uint32_t)blend_r << CHANNEL_SHIFT(0)) |
|
||||||
(blend_g << 8) |
|
((uint32_t)blend_g << CHANNEL_SHIFT(1)) |
|
||||||
(blend_b << 16) |
|
((uint32_t)blend_b << CHANNEL_SHIFT(2)) |
|
||||||
((uint32_t)blend_a << 24);
|
((uint32_t)blend_a << CHANNEL_SHIFT(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +255,7 @@ static void BlendPixelRowNonPremult(uint32_t* const src,
|
|||||||
const uint32_t* const dst, int num_pixels) {
|
const uint32_t* const dst, int num_pixels) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num_pixels; ++i) {
|
for (i = 0; i < num_pixels; ++i) {
|
||||||
const uint8_t src_alpha = (src[i] >> 24) & 0xff;
|
const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
if (src_alpha != 0xff) {
|
if (src_alpha != 0xff) {
|
||||||
src[i] = BlendPixelNonPremult(src[i], dst[i]);
|
src[i] = BlendPixelNonPremult(src[i], dst[i]);
|
||||||
}
|
}
|
||||||
@ -264,7 +272,7 @@ static WEBP_INLINE uint32_t ChannelwiseMultiply(uint32_t pix, uint32_t scale) {
|
|||||||
|
|
||||||
// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
|
// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
|
||||||
static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
|
static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
|
||||||
const uint8_t src_a = (src >> 24) & 0xff;
|
const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
return src + ChannelwiseMultiply(dst, 256 - src_a);
|
return src + ChannelwiseMultiply(dst, 256 - src_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +282,7 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
|
|||||||
int num_pixels) {
|
int num_pixels) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num_pixels; ++i) {
|
for (i = 0; i < num_pixels; ++i) {
|
||||||
const uint8_t src_alpha = (src[i] >> 24) & 0xff;
|
const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
|
||||||
if (src_alpha != 0xff) {
|
if (src_alpha != 0xff) {
|
||||||
src[i] = BlendPixelPremult(src[i], dst[i]);
|
src[i] = BlendPixelPremult(src[i], dst[i]);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user