源碼
#[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(高動態范圍)顏色的場景。