• 如果您查看有关默认混合模式 ('source-over') 的 canvas'context2D 规范:
http://dev.w3.org/fxtf/compositing-1/#simplealphacompositing
你会看到使用的公式是(为了清楚起见,我重命名了变量):
colorOut = prevColor x prevAlpha + newColor x newAlpha x (1 - prevAlpha)
对于生成的 alpha:
αlphaOut = prevAlpha + newAlpha x (1 - prevAlpha)
请注意,
a) 出乎意料的是,公式不是线性的(由于:newAlpha x (1 - prevAlpha) 因子)。
b) 一个点的 r,g,b 值两个都较小和降低了 alpha。所以在重新使用它时,它
将为最终图像贡献 square(0.6)==0.36。 (……完全违反直觉……)
• 那么,您的 60% / 40% 抽奖会发生什么?
1) 使用 alpha = 60% 绘制图像 A。
上面的公式给出:
colorOut = color_A * 0.6 ;
alphaOut = 0.6 ;
2) 使用 alpha = 40% 绘制图像 B
colorOut = color_A * 0.6 * 0.6 + color_B x 0.4 x (0.4);
alphaOut = 0.6 + 0.4 * 0.4;
所以最终公式是 ==>
colorOut = 0.36 * color_A + 0.16 * color_B ;
alphaOut = 0.76 ;
您会发现,这根本不是您所期望的 60/40 组合。
• 如何解决?
1) 您可以使用 getImageData / putImageData 手动完成。请注意跨域问题:如果您的图像不是来自您的域,则它们的 imageData 将为空。对于性能,与执行工作的画布(= GPU)相比,押注 50+ 的减速因素。根据图像大小/计算能力/浏览器,可能无法实现“实时”(=60fps)。但是你有完全的控制权。
2) 但是如果你现在看一下'ligther' 复合模式,似乎我们有我们的家伙:
http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_plus
公式现在是:
colorOut = prevColor x prevAlpha + newColor x newAlpha
对于生成的 alpha:
αlphaOut = prevAlpha + newAlpha
您会发现这是一个简单的“加号”运算符,非常适合您的要求。
所以解决方案是:
- 保存 ctx。
- 设置更轻的复合模式。
- 以 60% 的 alpha 绘制第一张图像。
- 以 40% alpha 绘制第二张图像。
- 恢复 ctx。
最后的话:如果你想检查最终的 alpha 是否正确(==255),请使用那种函数:
function logAlpha(ctx,x,y) {
var imDt = ctx.getImageData(x,y,1,1).data;
if (!(imDt[0] || imDt[1] || imDt[2])) console.log('null point. CORS issue ?');
console.log(' point at (' +x+ ',' +y+ ') has an alpha of ' + imDt[3] ) ;
}