我需要在相同的图像上绘制2个相同图像的变体,其alpha值加起来为1.
例如:
- imageA
的字母为0.4
,而imageB
的字母为0.6
。
- 所需的结果是完全不透明的图像(每个像素的1.0
的alpha),显示为imageB
的60%混合,以及imageA
的40%混合。
但是,我认为默认情况下html5画布使用的是混合模式,而不是添加alpha混合图像,因此使用低于1的alpha绘制的两个内容不会加起来为1。
我尝试了所有不同的合成模式,以及Adobe混合模式,但没有一个具有所需的结果
一个简单的测试用例是绘制一个洋红色矩形两次,两者都是0.5
的alpha。我希望得到的像素为rgb(255, 0, 255)
。但是,结果略显透明。
有谁知道实现这一结果的某种方式?
答案 0 :(得分:3)
•如果你看一下关于默认混合模式的canvas'context2D规范('source-over'):
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)图像A绘制为alpha = 60%。 上面的公式给出了:
colorOut = color_A * 0.6 ;
alphaOut = 0.6 ;
2)用α= 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手动完成。请注意Cross-Origin问题:如果您的图片不是来自您的域,则他们的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%的阿尔法绘制第一张图像
- 以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] ) ;
}