当缩放一个 < 画布 > 时禁用插值

注意 : 这与如何呈现 现有的画布元素在放大时呈现没有和如何呈现 放在帆布表面上的线条或图形有关。换句话说,这与 比例元素插值有关,而与画布上绘制的图形的 反锯齿无关。我关心的不是浏览器如何绘制线条,而是浏览器在放大时如何呈现画布元素 本身


是否有一个画布属性或浏览器设置,我可以通过编程来禁用插值时缩放 <canvas>元素?跨浏览器的解决方案是理想的,但并非必不可少; 基于 Webkit 的浏览器是我的主要目标。表现很重要。

这个问题 非常相似,但是没有充分说明这个问题。不管怎样,我试过 image-rendering: -webkit-optimize-contrast但没有用。

该应用程序将是一个“复古”8位风格的游戏写在 HTML5 + JS,使它清楚我需要什么。


为了说明这一点,这里有一个例子

假设我有一张21x21的画布。

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

... 它的 css 使得元素变大了5倍(105x105) :

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 interpolates scaled canvas elementsA non-interpolated version

83202 次浏览

编辑7/31/2012-这个功能现在在画布规范中:

Https://stackoverflow.com/a/11751817/154112

古老的答案就在下面。


根据你所期望的效果,你可以这样选择:

var can = document.getElementById('b');
var ctx = can.getContext('2d');
ctx.scale(5,5);
$('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();
});

Http://jsfiddle.net/wa95p/

这就造成了这样的结果:

enter image description here

可能不是你想要的。但是如果你只是想要零模糊,那么这就是最好的选择,所以我会提供它,以防万一。

一个更困难的选择是使用像素操作,并为这项工作自己编写一个算法。第一个图像的每个像素成为新图像上的一个5x5像素块。利用图像数据不会太难。

但是仅仅使用 Canvas 和 CSS 无法帮助您按照您希望的效果将其中一个扩展到另一个。

最后更新: 2014-09-12

是否有一个画布属性或浏览器设置,我可以通过编程来禁用插值时缩放元素?

答案是 也许有一天。现在,你将不得不采取黑客攻击来得到你想要的东西。


image-rendering

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

图像呈现属性为用户代理提供了一个提示,告诉用户代理在缩放图像时需要保留图像的哪些方面,以帮助用户代理选择适当的缩放算法。

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

像素化:

当缩放图像时,必须使用“最近邻”或类似的算法,使图像看起来只是由非常大的像素组成。当按比例缩小时,这和 auto 是一样的。

标准的,跨浏览器的?

因为这只是一个 工作草稿,所以不能保证它会成为标准。浏览器支持目前最多只能算是参差不齐。

Mozilla Developer Network 有 一个相当彻底的网页,致力于当前的艺术状态,我强烈推荐阅读。

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,写了一篇非常深入的文章(他甚至在研究中引用了这个问题)。

有关依赖于 imageSmoothingEnabled属性的基于画布的解决方案,请参见 西蒙的回答(在较老的浏览器中不可用,但比预缩放更简单,并且受到相当广泛的支持)。

现场演示

如果你想测试 MDN 文章中讨论的关于 canvas元素的 CSS 属性,我已经制作了 这把小提琴,它应该像这样显示,模糊与否,取决于你的浏览器: a 4:1 (64x64 to 256x256) image of an isometric pixel-art style TV

在谷歌铬,画布图像模式不插值。

下面是一个根据 Namuol 答案 http://jsfiddle.net/pGs4f/编辑的工作示例

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);

新答案2012年7月31日

这是最终在画布规格!

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

图像平滑最近才被添加到画布规范中,并不是所有的浏览器都支持,但是一些浏览器已经实现了这个属性的供应商前缀版本。火狐浏览器中有 mozImageSmoothingEnabled,Chrome 浏览器和 Safari 浏览器中有 webkitImageSmoothingEnabled,将它们设置为 false 将阻止反锯齿的发生。不幸的是,在撰写本文时,IE9和 Opera 还没有实现这个属性,无论是前缀还是其他。


预览: 译自: 美国《科学》杂志网站(http://JSFiddle.net/ikaruss/VAXrL/1164/)

结果:

enter image description here

Saviski 的解释 给你的变通方法是有希望的,因为它适用于:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 m Windows 7
  • Chromium 18.0.1025.168(Developer Build 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

但是在以下情况下不起作用,但是使用 CSS 图像渲染可以达到同样的效果:

  • Firefox15.0.1 Mac OS X 10.6.8(图像渲染:-moz-Crisp-edge 在 这个中可以工作)
  • Opera 12.02 Mac OS X 10.6.8(图像渲染:-o-Crisp-edge 在 这个中可以工作)
  • Opera 12.02 Windows 7(图像渲染:-o-Crisp- 边缘在 这个中工作)

问题在于这些,因为 ctx.XXXImageSmoothingEnable 不起作用,图像渲染也不起作用:

  • Safari 5.1.7 Mac OS X 10.6.8
  • Safari 5.1.7 Windows 7(图像渲染:-webkit-Optim- 对比度不工作)
  • IE9Windows7(- ms-Internationation- 模式: 最近邻不工作)

您所要做的就是在 <canvas>上设置 image-rendering: pixelated CSS 属性。现在所有浏览器都支持这一点。(https://caniuse.com/mdn-css_properties_image-rendering_pixelated)