mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-30 18:05:36 +01:00 
			
		
		
		
	anim_decode: fix alpha blending with big-endian
images are decoded in RGBA/BGRA, but represented as uint32_t during the
blend process; this fixes the channel extraction
Bug: webp:548
Change-Id: Ie74aa43d8f87d3552d5afc0abba466335f5d1617
(cherry picked from commit e4886716d3)
			
			
This commit is contained in:
		| @@ -23,6 +23,14 @@ | ||||
|  | ||||
| #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); | ||||
| static void BlendPixelRowNonPremult(uint32_t* const src, | ||||
|                                     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 uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a; | ||||
|   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. | ||||
| 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) { | ||||
|     return dst; | ||||
|   } 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: | ||||
|     // dst_factor_a = (dst_a * (255 - src_a)) / 255. | ||||
|     const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8; | ||||
|     const uint8_t blend_a = src_a + dst_factor_a; | ||||
|     const uint32_t scale = (1UL << 24) / blend_a; | ||||
|  | ||||
|     const uint8_t blend_r = | ||||
|         BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 0); | ||||
|     const uint8_t blend_g = | ||||
|         BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 8); | ||||
|     const uint8_t blend_b = | ||||
|         BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 16); | ||||
|     const uint8_t blend_r = BlendChannelNonPremult( | ||||
|         src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(0)); | ||||
|     const uint8_t blend_g = BlendChannelNonPremult( | ||||
|         src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(1)); | ||||
|     const uint8_t blend_b = BlendChannelNonPremult( | ||||
|         src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(2)); | ||||
|     assert(src_a + dst_factor_a < 256); | ||||
|  | ||||
|     return (blend_r << 0) | | ||||
|            (blend_g << 8) | | ||||
|            (blend_b << 16) | | ||||
|            ((uint32_t)blend_a << 24); | ||||
|     return ((uint32_t)blend_r << CHANNEL_SHIFT(0)) | | ||||
|            ((uint32_t)blend_g << CHANNEL_SHIFT(1)) | | ||||
|            ((uint32_t)blend_b << CHANNEL_SHIFT(2)) | | ||||
|            ((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) { | ||||
|   int 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) { | ||||
|       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. | ||||
| 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); | ||||
| } | ||||
|  | ||||
| @@ -274,7 +282,7 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst, | ||||
|                                  int num_pixels) { | ||||
|   int 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) { | ||||
|       src[i] = BlendPixelPremult(src[i], dst[i]); | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user