用html5画布将两个图像混合 [英] Blending two images with html5 canvas
问题描述
我需要绘制两个相同图片的变体,其alpha值加起来为1.
I need to draw 2 variations of the same image on top of each other, whose alpha values add up to 1.
例如:
- imageA
具有 0.4
的alpha值,而 imageB
具有 0.6 的alpha。
- 所需的结果是一个完全不透明的图像(α 1.0
为每个像素),其显示为 imageB
的60%混合,以及 imageA 的40%混合>。
For example :
- imageA
has an alpha of 0.4
, while imageB
has an alpha of 0.6
.
- The desired result is a completely opaque image (alpha of 1.0
for each pixel), which appears as a 60% blend of imageB
, and a 40% blend of imageA
.
然而,我相信html5画布默认使用混合模式,而不是添加在alpha混合图像,所以两个东西绘制alphas低于1不会添加最多为1.
我尝试了所有不同的合成模式,以及Adobe混合模式,但没有一个具有所需的结果。
一个简单的测试用例是绘制一个洋红色矩形两次,两者的α 0.5
。我的愿望是得到的像素为 rgb(255,0,255)
。然而,结果是稍微透明。
However, I believe that the html5 canvas by default uses a blend mode other than add on alpha blended images, so two things drawn with alphas below 1 will not add up to 1.
I've tried all the different compositing modes, along with the Adobe blend modes, but none of them have the desired result.
A simple test case is to draw a magenta rect twice, both with alpha of 0.5
. My desire is for the resulting pixels to be rgb(255, 0, 255)
. However, the result is slightly transparent.
有没有人知道实现这个结果的方法?
Does anyone know some way of achieving this result?
推荐答案
•如果你看一下关于默认混合模式('source-over')的canvas'context2D规范:
• If you look at the canvas'context2D specification about the default blending mode ('source-over'):
http://dev.w3.org/fxtf/compositing-1/#simplealphacompositing
您将看到使用的公式是(为了清晰起见,我重命名了变量):
You'll see the formula used is ( i renamed the variables for clarity) :
colorOut = prevColor x prevAlpha + newColor x newAlpha x (1 - prevAlpha)
b
$ b
And for resulting alpha :
αlphaOut = prevAlpha + newAlpha x (1 - prevAlpha)
请注意,
意外的是,公式不是线性的(由于:newAlpha x(1 - prevAlpha)因子)。
b)a点具有较小的r,g,b值和缩小的α。所以当重新使用它,它
将贡献为平方(0.6)== 0.36到最终的图像。 (...完全违反直觉...)
Notice that,
a) unexpectedly, the formula is not linear (due to : newAlpha x (1 - prevAlpha) factor ).
b) a point has both smaller r,g,b values and reduced alpha. So when re-using it, it
will contribute for square(0.6)==0.36 to the final image. (...completely counter-intuitive...)
•那么,你的60%/ 40%抽奖会发生什么?
• So what does happen for your 60% / 40% draws ?
1)image A以alpha = 60%绘制。
上面的公式给出:
1) image A is drawn with alpha = 60%. The formula above gives :
colorOut = color_A * 0.6 ;
alphaOut = 0.6 ;
2)image B用alpha = 40%绘制
2) image B is drawn with alpha = 40%
colorOut = color_A * 0.6 * 0.6 + color_B x 0.4 x (0.4);
alphaOut = 0.6 + 0.4 * 0.4;
所以最后的公式是==>
So final formula is ==>
colorOut = 0.36 * color_A + 0.16 * color_B ;
alphaOut = 0.76 ;
你看到的不是所有的 60/40混音。
You see that's not at all the 60/40 mix you expected.
•如何解决?
1)您可以使用getImageData / putImageData手动执行。请注意跨原始问题:如果您的图片不是来自您的域,他们的imageData将为空。对于表演,打赌一个50 +减速因子相比,画布(= GPU)做这项工作。 实时(= 60fps)可能不可能,具体取决于图像大小/计算能力/浏览器。但你有完全的控制。
1) You can do it by hand using getImageData / putImageData. Be aware of the Cross-Origin issue : if your images don't come from your domain, their imageData will be empty. For performances, bet on a 50+ slow-down factor compared to the canvas (= the GPU) doing the job. 'real time' (=60fps) might not be possible depending on image size/computing power/browser. But you have full control.
2)但是如果你现在看看'ligther'复合模式,看起来我们有我们的家伙:
2) But if you now look at the 'ligther' composite mode, it seems we have our guy :
http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_plus
公式现在是:
colorOut = prevColor x prevAlpha + newColor x newAlpha
对于生成的alpha:
And for resulting alpha :
αlphaOut = prevAlpha + newAlpha
这是一个简单的加号运算符,非常适合您的要求。
所以解决方案是:
- 保存ctx。
- 设置较轻的复合模式。
- 以60%alpha绘制第一张图片。
- 以40%alpha绘制第二张图片。
- 还原ctx。
You see that this is a simple 'plus' operator, perfect for your requirement.
So solution is :
- save ctx.
- set lighter composite mode.
- draw first image at 60% alpha.
- draw second image at 40% alpha.
- restore ctx.
最后的话:如果你想检查最后的alpha是否正确(== 255),使用那种函数:
Last words : if you want to check that the final alpha is right (==255), use that kind of function :
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] ) ;
}
这篇关于用html5画布将两个图像混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!