Javascript 用html5画布混合两幅图像

Javascript 用html5画布混合两幅图像,javascript,html,canvas,html5-canvas,alphablending,Javascript,Html,Canvas,Html5 Canvas,Alphablending,我需要画两个相同图像的变体,它们的alpha值加起来等于1 例如: -imageA的alpha为0.4,而imageB的alpha为0.6。 -理想的结果是每个像素的完全不透明图像alpha为1.0,显示为imageB的60%混合,imageA的40%混合 然而,我相信html5画布在默认情况下使用的是混合模式,而不是添加alpha混合图像,因此,使用低于1的alpha绘制的两个东西加起来不会达到1。 我尝试了所有不同的合成模式,以及Adobe混合模式,但没有一个达到预期的效果。 一个简单的测试

我需要画两个相同图像的变体,它们的alpha值加起来等于1

例如: -imageA的alpha为0.4,而imageB的alpha为0.6。 -理想的结果是每个像素的完全不透明图像alpha为1.0,显示为imageB的60%混合,imageA的40%混合

然而,我相信html5画布在默认情况下使用的是混合模式,而不是添加alpha混合图像,因此,使用低于1的alpha绘制的两个东西加起来不会达到1。 我尝试了所有不同的合成模式,以及Adobe混合模式,但没有一个达到预期的效果。 一个简单的测试用例是绘制两次洋红色矩形,两者的alpha值均为0.5。我希望得到的像素是rgb255、0、255。然而,结果是略微透明的


有人知道实现这一结果的方法吗?

•如果您查看canvas关于默认混合模式“源代码结束”的context2D规范:

您将看到使用的公式是:为了清晰起见,我重命名了变量:

colorOut = prevColor x prevAlpha + newColor x newAlpha x (1 - prevAlpha)
对于生成的alpha:

αlphaOut = prevAlpha + newAlpha x (1 - prevAlpha)
 αlphaOut = prevAlpha + newAlpha 
注意,, a出乎意料的是,由于:newAlpha x 1-prevAlpha因子,公式不是线性的。 b a点既有较小的r、g、b值,又有较小的α值。因此,当重新使用它时,它 将为最终图像贡献平方0.6==0.36。。。完全违反直觉

•那么,您的60%/40%提款会发生什么情况

1图像A以α=60%绘制。 上述公式给出:

 colorOut = color_A * 0.6 ;
 alphaOut = 0.6 ;
2图像B以alpha=40%绘制

 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手动完成。请注意跨源问题:如果您的图像不是来自您的域,则其图像数据将为空。对于性能,与canvas=执行任务的GPU相比,赌50+的减速系数根据图像大小/计算能力/浏览器,实时'=60fps可能不可能。但你有完全的控制权

2但如果你现在看看“利瑟”复合模式,我们似乎有了我们的人:

现在的公式是:

colorOut = prevColor x prevAlpha + newColor x newAlpha 
对于生成的alpha:

αlphaOut = prevAlpha + newAlpha x (1 - prevAlpha)
 α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] ) ;
 }

“打火机”对我有用。非常感谢!非常翔实的回答。