【问题标题】:Weird HTML 5 Canvas Antialiasing奇怪的 HTML 5 画布抗锯齿
【发布时间】:2015-12-17 11:48:30
【问题描述】:

我一直在玩画布元素,发现当我尝试在某些宽度/高度配置中绘制 NxN 均匀的纯色单元格时,它们之间会出现模糊的白色线条。

例如,这个画布应该看起来是黑色的,但包含某种 grid,我猜这是浏览器中抗锯齿错误的结果。

我只想说,这个错误只出现在 一些 配置中,但我想彻底摆脱它。有什么办法可以规避这种情况吗?您是否曾在画布中遇到过抗锯齿问题?

我制作了this fiddle,它演示了这个问题,并允许您使用画布的尺寸和单元格的数量。它还包含我用来绘制单元格的代码,这样您就可以检查它并告诉我是否做错了什么。

var ctx = canvas.getContext('2d');  
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
for (var i = 0; i < numberOfCells; ++i) {
    for (var j = 0; j < numberOfCells; ++j) {
    ctx.fillStyle = '#000';
    ctx.fillRect(j * cellWidth, i * cellHeight, cellWidth, cellHeight);
  }
}

提前致谢,

彼得。

【问题讨论】:

  • 您好 Petr,您似乎忘记提供小提琴链接了,请您更新一下
  • 刚刚注意到了。对不起,给你! :)
  • 我相信,一个常见的技巧是在开始时将整个画布变换一个像素以避开这一点。
  • 确实有道理,300 / 70 = 4.285... 将使任何边缘反锯齿,因此会出现一条线。它似乎做了预期的事情,因为四舍五入......
  • 你可以在这里找到解决方案Filling the gaps

标签: javascript html canvas antialiasing


【解决方案1】:

jsFiddle : https://jsfiddle.net/ngxjnywz/2/

javascript的sn-p

var cellWidth = Math.ceil(canvasWidth / numberOfCells);
var cellHeight = Math.ceil(canvasHeight / numberOfCells);

根据宽度、高度和您的 numberOfCells,您有时会得到一个...假设 4.2 是 4,但是这会显示错误,并且会出现 1 像素的空白行。因此,您需要做的就是使用Math.ceil 函数,这将导致您的 cellWidth 和 cellHeight 始终为较大的数字,并且您将不再出现空行

【讨论】:

  • 不幸的是,只有当线条平行于 X 或 Y 轴时,舍入才有效,也不考虑可能应用的任何变换。
  • 这是一个非常好的和简单的解决方案。它可能会有点混乱,因为单元格会开始重叠,这可能会导致绘图顺序突然变得相关,但由于相同的 ceiled 'cellWidth' 将用于偏移绘图过程,这将被阻止。
  • 我刚刚试过“ctx.fillRect(j * cellWidth + 151, i * cellHeight + 77, cellWidth, cellHeight);”它可以正常工作但是我可以确认网格上的任何“变换”都会重现线条,但是如果你在网格之后变换任何东西都可以,看看我的链接jsfiddle.net/ngxjnywz/4
【解决方案2】:

最好的解决方案是在所有填充周围添加一个 0.5 像素宽的描边,使用与填充相同的样式并偏移所有绘图,以便在像素中心而不是左上角进行渲染。

如果您添加缩放或平移,则必须调整坐标,以便您仍然为绘图坐标提供中心。

最终您只能减少伪影,但在许多情况下您将无法完全移除它们。

此答案向您展示了如何删除未转换画布的工件。 How to fill the gaps

【讨论】:

  • 这是一个看起来相当复杂的过程。在我的特定设置中,我将不得不完全重新考虑我的网格绘图的数学。
  • @PetrMánek 没错,但在其他情况下,这确实是最简单的解决方案 - 只需将 .5 添加到所有坐标。
  • @PetrMánek。半像素技巧以重新设计为代价效果很好。另一种解决方法是在第二个画布上创建“构建块”和assemble your design from those building blocks
  • 尝试将绘图偏移 0.5px,但问题并没有消失。虽然我画布中的线条和文本现在看起来更清晰了,但在某些情况下仍然可以看到分隔各个方块的细网格线。当我添加 0.5px 宽的笔画时,一切都开始显得笨重和凌乱。
  • 您可以尝试各种ctx.drawImage(largeCanvas, 0, 0, canvas.width, canvas.height) 和 ctx.imageSmoothingEnabled; = true; 将该画布绘制到原始画布上,这将进一步减少伪影。或者使用ctx,getImageData() 并自己逐像素渲染这些框。如果它只是盒子,那么就不会涉及那么多。
【解决方案3】:

在阅读并尝试了几种方法后,我决定提出自己的方法。我创建了另一个(虚拟)画布,其整数尺寸对应于网格中的单元格数。

在其中绘制完所有单元格后,我在主画布上调用 context.drawImage() 并将虚拟画布作为参数传递给偏移量和缩放参数,以使其适合我的绘图的其余部分。假设浏览器会将虚拟画布的图像作为一个整体(而不是单个单元格)进行缩放,我希望摆脱不需要的分隔线。

尽管我很努力,但线条仍然存在。有什么建议吗?

这是展示我技术的小提琴:https://jsfiddle.net/ngxjnywz/5/

【讨论】:

  • 我找到了罪魁祸首。事实证明,只要我不将辅助画布移动 0.5 像素(如另一个答案中所建议),这种方法就可以工作。删除context.translate(0.5, 0.5) 后,其他一切都到位了。
猜你喜欢
  • 2011-08-27
  • 1970-01-01
  • 2016-04-24
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
相关资源
最近更新 更多