javascript - 使用 html5 canvas 混合两个图像

标签 javascript html canvas html5-canvas alphablending

我需要在彼此之上绘制同一图像的 2 个变体,其 alpha 值加起来为 1。

例如:
-imageA alpha 为0.4 ,而imageB alpha 为0.6 .
- 所需的结果是完全不透明的图像(每个像素的 alpha 为 1.0),它显示为 imageB 的 60% 混合,以及 40% 的 imageA 混合物.

但是,我相信 html5 Canvas 默认使用混合模式,而不是在 alpha 混合图像上添加,因此使用低于 1 的 alpha 绘制的两个内容相加不会等于 1。
我尝试了所有不同的合成模式以及 Adob​​e 混合模式,但没有一个达到预期的结果。
一个简单的测试用例是绘制一个洋红色矩形两次,alpha 均为 0.5 。我的愿望是生成的像素为 rgb(255, 0, 255) 。然而,结果是稍微透明的。

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

最佳答案

• 如果您查看有关默认混合模式(“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) 图像 A 是用 alpha = 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 手动完成。请注意跨源问题:如果您的图像不是来自您的域,则它们的 imageData 将为空。就性能而言,与完成这项工作的 Canvas (= GPU)相比,速度会慢 50 以上。根据图像大小/计算能力/浏览器,“实时”(=60fps) 可能无法实现。但你拥有完全的控制权。

2)但如果你现在看看“更轻”的复合模式,似乎我们有我们的人:

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] ) ;
 }

关于javascript - 使用 html5 canvas 混合两个图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26200800/

相关文章:

html - 如何删除 HTML 中 span 标签之间的分界线

javascript - 在 Canvas 中旋转 Sprite

javascript - 简单的 Canvas 动画

canvas - Fabricjs 使用变量设置顶部/左侧

javascript - 调用覆盖的 .click() 方法

javascript - 在加载时显示 Bootstrap 工具提示并在几秒钟后自动隐藏

javascript - 为什么 Firebase `accessToken` 位于如此奇怪的标题下?

html - 如何内联显示文件输入?

javascript - 如何使用 if 条件测试 Google map 地点类型

html - 带有嵌套 <a> 和 <img> 标签的 <li> 标签之间的等距问题