源码
rust
use super::constant::BILINEAR_INTERPOLATION_BITS;
// Inspired by Filter_32_opaque from Skia.
fn bilinear_interpolation(
tl: u32,
tr: u32,
bl: u32,
br: u32,
mut distx: u32,
mut disty: u32,
) -> u32 {
let distxy;
let distxiy;
let distixy;
let distixiy;
let mut lo;
let mut hi;
distx <<= 4 - BILINEAR_INTERPOLATION_BITS;
disty <<= 4 - BILINEAR_INTERPOLATION_BITS;
distxy = distx * disty;
distxiy = (distx << 4) - distxy; // distx * (16 - disty)
distixy = (disty << 4) - distxy; // disty * (16 - distx)
// (16 - distx) * (16 - disty)
// The intermediate calculation can underflow so we use
// wrapping arithmetic to let the compiler know that it's ok
distixiy = (16u32 * 16)
.wrapping_sub(disty << 4)
.wrapping_sub(distx << 4)
.wrapping_add(distxy);
lo = (tl & 0xff00ff) * distixiy;
hi = ((tl >> 8) & 0xff00ff) * distixiy;
lo += (tr & 0xff00ff) * distxiy;
hi += ((tr >> 8) & 0xff00ff) * distxiy;
lo += (bl & 0xff00ff) * distixy;
hi += ((bl >> 8) & 0xff00ff) * distixy;
lo += (br & 0xff00ff) * distxy;
hi += ((br >> 8) & 0xff00ff) * distxy;
((lo >> 8) & 0xff00ff) | (hi & !0xff00ff)
}
代码分析
这个函数实现了双线性插值算法,用于在四个已知像素点(tl, tr, bl, br)之间插值计算一个新的像素值。该代码参考Skia图形库中Filter_32_opaque函数。
参数说明
-
tl: 左上(top-left)像素值
-
tr: 右上(top-right)像素值
-
bl: 左下(bottom-left)像素值
-
br: 右下(bottom-right)像素值
-
distx: x方向的插值距离(0-15)
-
disty: y方向的插值距离(0-15)
算法步骤
1.距离调整:
rust
distx <<= 4 - BILINEAR_INTERPOLATION_BITS;
disty <<= 4 - BILINEAR_INTERPOLATION_BITS;
将输入的distx和disty从BILINEAR_INTERPOLATION_BITS精度调整到4位精度(0-15)。
- 计算权重因子:
-
distxy: distx * disty
-
distxiy: distx * (16 - disty)
- distixy: disty * (16 - distx)
- distixiy: (16 - distx) * (16 - disty)
- 分离颜色通道计算:
函数将32位颜色值分为两个16位部分处理:
-
lo: 处理蓝色(低8位)和红色(高8位)通道
-
hi: 处理绿色(低8位)和alpha(高8位)通道
4.加权求和:
对四个角的像素值按照计算出的权重进行加权求和。
- 合并结果:
rust
((lo >> 8) & 0xff00ff) | (hi & !0xff00ff)
将计算结果重新组合成32位像素值。
技术细节
-
使用wrapping_操作防止中间计算溢出
-
使用位操作高效处理颜色通道
-
假设输入像素是不透明的(alpha通道为0xff)
这个函数在图像缩放、旋转等变换中非常有用,可以平滑地计算出新位置的像素值,避免锯齿效果。