源码
#[inline]pub fn over_exact(self, dst: Argb) -> Argb {let a = 255 - self.alpha32();let t = dst.rb() * a + 0x80_00_80;let mut rb = (t + ((t >> 8) & Argb::MASK)) >> 8;rb &= Argb::MASK;rb += self.rb();// saturaterb |= 0x1000100 - ((rb >> 8) & Argb::MASK);rb &= Argb::MASK;let t = dst.ag() * a + 0x800080;let mut ag = (t + ((t >> 8) & Argb::MASK)) >> 8;ag &= Argb::MASK;ag += self.ag();// saturateag |= 0x1000100 - ((ag >> 8) & Argb::MASK);ag &= Argb::MASK;Argb((ag << 8) + rb)}
代码分析
这段代码实现了一个精确的 Alpha 混合(“over” 操作)函数,使用除以 255 的精确计算,并处理了超亮像素的饱和问题。
与近似版本 (over) 的主要区别
-
精确除法:使用 +0x80 技巧实现四舍五入的除以 255(而不是近似除以 256)
-
饱和处理:确保混合结果不会超过最大颜色值(255)
-
超亮像素支持:能正确处理亮度值超过标准范围的情况
详细步骤解析
- 红蓝通道处理 (rb)
let a = 255 - self.alpha32(); // 计算不透明度补数 (1-α)
let t = dst.rb() * a + 0x80_00_80; // 乘法并加四舍五入因子
let mut rb = (t + ((t >> 8) & Argb::MASK)) >> 8; // 精确除以255
rb &= Argb::MASK; // 掩码确保正确位范围rb += self.rb(); // 加上源颜色值// 饱和处理
rb |= 0x1000100 - ((rb >> 8) & Argb::MASK);
rb &= Argb::MASK;
-
0x80_00_80 是实现四舍五入除以255的技巧(相当于加0.5后取整)
-
饱和处理确保任何超过255的值会被截断为255
- Alpha和绿通道处理 (ag)
let t = dst.ag() * a + 0x800080;
let mut ag = (t + ((t >> 8) & Argb::MASK)) >> 8;
ag &= Argb::MASK;
ag += self.ag();// 饱和处理
ag |= 0x1000100 - ((ag >> 8) & Argb::MASK);
ag &= Argb::MASK;
-
处理方式与红蓝通道相同
-
同时处理Alpha和绿色通道(因为它们被打包在同一个32位值中)
- 最终组合
Argb((ag << 8) + rb)
将处理后的Alpha/绿通道和红蓝通道重新组合成ARGB颜色
数学原理
这个函数实现了精确的Alpha混合公式:
result = src + dst × (1 - src_alpha)
其中:
-
使用 (x * a + 0x80) >> 8 近似 (x * a) / 255(带四舍五入)
-
饱和处理确保各通道值不超过255
性能考虑
-
虽然比近似版本计算量更大,但更精确
-
仍然使用位操作和移位来优化性能
-
标记为 #[inline] 建议内联
-
分开处理rb和ag通道是为了并行化或特定硬件优化
这段代码特别适合需要高精度颜色混合或处理HDR(高动态范围)颜色的场景。