用html5画布将两个图像混合 [英] Blending two images with html5 canvas

查看:228
本文介绍了用html5画布将两个图像混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要绘制两个相同图片的变体,其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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆