为什么在缩放 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,看这个就这事)。
我在 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,看这个