【学Rust写CAD】34 精确 Alpha 混合函数(argb.rs补充方法)

发布于:2025-04-07 ⋅ 阅读:(19) ⋅ 点赞:(0)

源码

#[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();

        // saturate
        rb |= 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();

        // saturate
        ag |= 0x1000100 - ((ag >> 8) & Argb::MASK);
        ag &= Argb::MASK;

        Argb((ag << 8) + rb)
    }

代码分析

这段代码实现了一个精确的 Alpha 混合(“over” 操作)函数,使用除以 255 的精确计算,并处理了超亮像素的饱和问题。

与近似版本 (over) 的主要区别
  1. 精确除法:使用 +0x80 技巧实现四舍五入的除以 255(而不是近似除以 256)

  2. 饱和处理:确保混合结果不会超过最大颜色值(255)

  3. 超亮像素支持:能正确处理亮度值超过标准范围的情况

详细步骤解析
  1. 红蓝通道处理 (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

  1. 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位值中)

  1. 最终组合
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(高动态范围)颜色的场景。