为什么在缩放 html5 canvas 中可以看到伪影?

Why are artifacts visible in a scaled html5 canvas?

我在 canvases 中看到了 this and this 关于删除抗锯齿的讨论,但我认为这不是一回事。

在按任意值缩放 html5 canvas 之后(即使其响应),我注意到如果我在相同位置绘制两个相同大小的矩形,第一个矩形缩放边的边缘保持可见。

我提供了一个示例片段,我在其中绘制了一个灰色矩形,然后在其顶部绘制了一个红色矩形。灰色矩形的左右边缘各有一条单像素的红色垂直线。我知道这可能看起来微不足道,但在我的情况下却非常明显。

我该如何解决这个问题?谢谢!

var example = document.getElementById("example");
var ctx = example.getContext('2d');

ctx.scale(1.13,1);

ctx.fillStyle = "LightGrey";
ctx.fillRect(10,10,50,30);

ctx.fillStyle = "Black";
ctx.font = "20px Arial";
ctx.fillText("< Looks good.",70,30);

ctx.fillStyle = "Red";
ctx.fillRect(10,50,50,30);

// This light grey rectangle should completely cover the previous red one, but it doesn't!
ctx.fillStyle = "LightGrey";
ctx.fillRect(10,50,50,30);

ctx.fillStyle = "Black";
ctx.font = "20px Arial";
ctx.fillText("< Do you see red?",70,70);
<canvas id="example"></canvas>

您正在 X 轴上将变换矩阵缩放 1.13 倍。

所以你的坐标 10 实际上会在真实像素矩阵的坐标 11.3 处结束。

您不能在部分像素上绘制,所以抗锯齿确实会在这里发挥作用。

那么为什么第一个看起来更好?

因为灰色和白色*的混合比红灰和白色的混合更中性。但即使是您的第一个矩形也是抗锯齿的。

只要放大你的 canvas 你就会看到,两边都有一个一像素的带,实际上是半透明的。

* "White" 这是页面背景之一

var example = document.createElement("canvas");
var ctx = example.getContext('2d');

ctx.scale(1.13,1);

ctx.fillStyle = "LightGrey";
ctx.fillRect(10,10,50,30);

ctx.fillStyle = "Red";
ctx.fillRect(10,50,50,30);

ctx.fillStyle = "LightGrey";
ctx.fillRect(10,50,50,30);

// draw bigger with no antialiasing
var z_ctx = zoomed.getContext('2d');
zoomed.width = example.width * 10;
zoomed.height = example.height * 10;
z_ctx.imageSmoothingEnabled = false;
z_ctx.drawImage(example, 0,0, zoomed.width, zoomed.height);
<canvas id="zoomed"></canvas>

那么如何避免呢?

好吧,避免在非整数像素坐标处进行填充。这意味着您还必须时刻注意上下文转换矩阵,而不仅仅是传递给绘图函数的值。

(Ps: 还请记住,中风是一种更邪恶的野兽,因为它从线的中间开始绘制,所以在这种情况下,您甚至必须考虑lineWidth,看这个就这事)。