HtmlCanvas + globalAlpha + 重叠 = 不正确的输出颜色
HtmlCanvas + globalAlpha + overlap = incorrect output color
我想画一堆相互重叠的几乎透明的白色矩形。
每个矩形的不透明度为 0.01
我有 100 个重叠的矩形,我希望输出结果是所有不透明度的总和。换句话说,我希望结果是白色的,没有任何不透明度。
但事实并非如此
- 为什么?
- 如何得到我想要的结果?
下面是一个极简代码来说明问题
let canvas = document.createElement("canvas");
canvas.width = canvas.height = 512;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.fillRect(0,0,512,512);
ctx.fillStyle = "#ffffff";
ctx.globalAlpha = 0.01;
for(let i=0;i<100;i++){
let n = i*3;
ctx.fillRect(n,n,512-n,512-n);
}
document.body.appendChild(canvas);
这是结果
这是 jsfiddle
https://jsfiddle.net/hsqpno04/
非常欢迎任何帮助!
要对两种 RGBA 颜色进行 alpha 混合(假设是正常混合模式和复合模式),一般公式为
out = alpha * new + (1 - alpha) * old
但是 out
必须是一个整数(在 0~255 范围内),所以我们必须在其上进行舍入(我猜舍入可能取决于实现以及它们如何存储颜色值).
如果我们取一个不那么显眼的 alpha
0.1,并保持白色,那么 new
就是 255(白色是 255, 255, 255),旧的是 0(透明),
第一步我们会有
out = round( 0.1 * 255 + (1 - 0.1) * 0 );
// => 26
我们将执行以下步骤
out = round( 0.1 * 255 + (1 - 0.1) * 26 );
// => 49
out = round( 0.1 * 255 + (1 - 0.1) * 49 );
// => 70
out = round( 0.1 * 255 + (1 - 0.1) * 70 );
// => 89
[...] // a few iterations later
// => 250
out = round( 0.1 * 255 + (1 - 0.1) * 250 );
// => 251
out = round( 0.1 * 255 + (1 - 0.1) * 251 );
// => 251
out = round( 0.1 * 255 + (1 - 0.1) * 251 );
// => 251
一旦你达到这个251, 251, 251
颜色值,无论你添加多少新层,它都不会再改变颜色值,因此你永远无法达到如果不透明度小于 0.5,则通过分层该颜色的半透明版本来获得完全不透明的颜色。
您的 0.01
值将需要更多迭代才能达到此稳定位置(153 对 38),但它会以较低的值 (206) 实现。
round( 0.01 * 255 + (1 - 0.01) * 206 )
// => 206
请注意,颜色通常在存储时预先乘以它们的 alpha,这可能会在这些数字中添加一些舍入误差。
我想画一堆相互重叠的几乎透明的白色矩形。
每个矩形的不透明度为 0.01
我有 100 个重叠的矩形,我希望输出结果是所有不透明度的总和。换句话说,我希望结果是白色的,没有任何不透明度。
但事实并非如此
- 为什么?
- 如何得到我想要的结果?
下面是一个极简代码来说明问题
let canvas = document.createElement("canvas");
canvas.width = canvas.height = 512;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.fillRect(0,0,512,512);
ctx.fillStyle = "#ffffff";
ctx.globalAlpha = 0.01;
for(let i=0;i<100;i++){
let n = i*3;
ctx.fillRect(n,n,512-n,512-n);
}
document.body.appendChild(canvas);
这是结果
这是 jsfiddle https://jsfiddle.net/hsqpno04/
非常欢迎任何帮助!
要对两种 RGBA 颜色进行 alpha 混合(假设是正常混合模式和复合模式),一般公式为
out = alpha * new + (1 - alpha) * old
但是 out
必须是一个整数(在 0~255 范围内),所以我们必须在其上进行舍入(我猜舍入可能取决于实现以及它们如何存储颜色值).
如果我们取一个不那么显眼的 alpha
0.1,并保持白色,那么 new
就是 255(白色是 255, 255, 255),旧的是 0(透明),
第一步我们会有
out = round( 0.1 * 255 + (1 - 0.1) * 0 );
// => 26
我们将执行以下步骤
out = round( 0.1 * 255 + (1 - 0.1) * 26 );
// => 49
out = round( 0.1 * 255 + (1 - 0.1) * 49 );
// => 70
out = round( 0.1 * 255 + (1 - 0.1) * 70 );
// => 89
[...] // a few iterations later
// => 250
out = round( 0.1 * 255 + (1 - 0.1) * 250 );
// => 251
out = round( 0.1 * 255 + (1 - 0.1) * 251 );
// => 251
out = round( 0.1 * 255 + (1 - 0.1) * 251 );
// => 251
一旦你达到这个251, 251, 251
颜色值,无论你添加多少新层,它都不会再改变颜色值,因此你永远无法达到如果不透明度小于 0.5,则通过分层该颜色的半透明版本来获得完全不透明的颜色。
您的 0.01
值将需要更多迭代才能达到此稳定位置(153 对 38),但它会以较低的值 (206) 实现。
round( 0.01 * 255 + (1 - 0.01) * 206 )
// => 206
请注意,颜色通常在存储时预先乘以它们的 alpha,这可能会在这些数字中添加一些舍入误差。