缩放 <canvas> 时禁用插值

新手上路,请多包涵

注意:这与 现有画布元素在放大时的呈现方式 有关,与线条或图形 在画布表面上的 呈现方式 无关。换句话说,这与 缩放元素插值 有关,与在画布上绘制的图形的 抗锯齿 无关。我不关心浏览器如何画线;我关心浏览器在放大时如何呈现 canvas 元素 _本身_。


是否有画布属性或浏览器设置我可以通过编程方式更改以在缩放 <canvas> 元素时禁用插值?跨浏览器的解决方案是理想的,但不是必需的;基于 Webkit 的浏览器是我的主要目标。性能非常重要。

这个问题 最相似,但没有充分说明问题。对于它的价值,我已经尝试过 image-rendering: -webkit-optimize-contrast 但无济于事。

该应用程序将是一个用 HTML5+JS 编写的“复古”8 位风格游戏,以明确我需要什么。


为了说明,这里有一个例子。 ( 现场版

假设我有一个 21x21 的画布……

 <canvas id='b' width='21' height='21'></canvas>

…具有使元素大 5 倍 (105x105) 的 css:

 canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */

我像这样在画布上画了一个简单的“X”:

 $('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

左边的图像是 Chromium (14.0) 渲染的。右边的图像是我想要的(手绘用于说明目的)。

Chrome 插入缩放的画布元素非插值版本

原文由 namuol 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 917
2 个回答

最后更新:2014-09-12

是否有画布属性或浏览器设置我可以通过编程方式更改以在缩放元素时禁用插值?

答案 _也许是某一天_。现在,您将不得不求助于 hack-arounds 来获得您想要的东西。


image-rendering

CSS3 的工作草案概述了一个新属性 image-rendering 应该做我想要的:

image-rendering 属性向 user-agent 提供了一个提示,即当图像被缩放时,图像的哪些方面是最重要的,以帮助 user-agent 选择合适的缩放算法。

该规范概述了三个可接受的值: autocrisp-edgespixelated

像素化:

放大图像时,必须使用“最近邻”或类似算法,这样图像看起来就好像是由非常大的像素简单组成的。缩小时,这与自动相同。

标准?跨浏览器?

由于这只是一个 _工作草案_,因此不能保证它会成为标准。浏览器支持目前充其量是不稳定的。

Mozilla 开发者网络有 一个非常详尽的页面专门介绍当前的技术水平,我强烈推荐阅读。

Webkit 开发人员最初选择 暂时将此实现为 -webkit-optimize-contrast ,但 Chromium/Chrome 似乎并未使用实现此功能的 Webkit 版本。

更新:2014-09-12

Chrome 38 现在支持 image-rendering: pixelated

Firefox 有一个 错误报告 打开得到 image-rendering: pixelated 实施,但 -moz-crisp-edges 目前有效。

解决方案?

因此,迄今为止最跨平台的、纯 CSS 的解决方案是:

 canvas {
  image-rendering: optimizeSpeed;             /* Older versions of FF          */
  image-rendering: -moz-crisp-edges;          /* FF 6.0+                       */
  image-rendering: -webkit-optimize-contrast; /* Safari                        */
  image-rendering: -o-crisp-edges;            /* OS X & Windows Opera (12.02+) */
  image-rendering: pixelated;                 /* Awesome future-browsers       */
  -ms-interpolation-mode: nearest-neighbor;   /* IE                            */
}

遗憾的是,这还不适用于所有主要的 HTML5 平台(尤其是 Chrome)。

当然,可以在 javascript 中使用最近邻插值将图像手动放大到高分辨率画布表面,甚至可以在服务器端预先缩放图像,但在我的情况下,这将非常昂贵,因此它不是一个可行的选择。

ImpactJS 使用纹理预缩放技术来解决所有这些 FUD。 Impact 的开发者 Dominic Szablewski 就此 写了一篇非常深入的文章(他甚至在他的研究中引用了这个问题)。

请参阅 Simon 对依赖于 imageSmoothingEnabled 属性的基于画布的解决方案的回答(在旧浏览器中不可用,但比预缩放更简单并且得到广泛支持)。

现场演示

如果您想测试 MDN 文章中关于 canvas 元素的 CSS 属性,我制作了 这个小提琴,它应该显示类似这样的内容,模糊与否,具体取决于您的浏览器: 等距像素艺术风格电视的 4:1(64x64 到 256x256)图像

原文由 namuol 发布,翻译遵循 CC BY-SA 3.0 许可协议

新答案 2012 年 7 月 31 日

这终于在画布规格中了!

该规范最近添加了一个名为 imageSmoothingEnabled 的属性,默认为 true 并确定在非整数坐标上绘制的图像或按比例绘制的图像是否将使用更平滑的算法。如果它设置为 false 则使用最近邻,产生不太平滑的图像,而只是使看起来更大的像素。

图像平滑最近才被添加到画布规范中,并非所有浏览器都支持,但一些浏览器已经实现了此属性的供应商前缀版本。在上下文中存在 mozImageSmoothingEnabled 在 Firefox 中和 webkitImageSmoothingEnabled 在 Chrome 和 Safari 中,并将它们设置为 false 将停止发生抗锯齿。不幸的是,在撰写本文时,IE9 和 Opera 尚未实现此属性、供应商前缀或其他方式。


预览: JSFiddle

结果:

在此处输入图像描述

原文由 Simon Sarris 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题