首页 > 解决方案 > 为什么在缩放的 html5 画布中可以看到工件?

问题描述

我已经看过这个这个关于在画布中删除抗锯齿的讨论,但我不认为这是一回事。

在将 html5 画布缩放任意值(即使其具有响应性)之后,我注意到如果我在相同位置绘制两个相同大小的矩形,第一个矩形的缩放边的边缘仍然可见。

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

我该如何解决?谢谢!

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>

标签: htmlcanvasantialiasing

解决方案


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

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

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

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

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

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

* 这里的“白色”是页面的背景之一

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:还要记住,stroke 是一个更邪恶的野兽,因为它从线条的中间开始绘制,所以在这种情况下,你甚至必须考虑 lineWidth,请参阅这个Q/A关于此事的问题)。


推荐阅读