缩放<canvas>时禁用插值

注意 :这与放大时现有canvas元素的渲染方式有关而不是如何将线条或graphics渲染到canvas表面上 。 换句话说,这一切都与缩放元素的 插值有关,并且与在canvas上绘制graphics的抗锯齿function无关。 我不关心浏览器是如何绘制线条的; 我关心浏览器在放大时如何渲染canvas元素本身


有一个canvas属性或浏览器设置,我可以改变编程禁用插值缩放<canvas>元素? 跨浏览器的解决scheme是理想的,但不是必需的; 基于Webkit的浏览器是我的主要目标。 性能非常重要。

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

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


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

假设我有一个21×21的canvas…

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

…有css,使元素5倍大(105×105):

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

我在canvas上画一个简单的“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内嵌缩放的画布元素非插值版本

最后更新:2014-09-12

有一个canvas属性或浏览器设置,我可以改变编程禁用插值时,缩放元素?

答案也许有一天 。 现在,你将不得不采取黑客手段来得到你想要的。


image-rendering

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

图像渲染属性向用户代理提供关于在缩放图像时图像的哪些方面最重要的提示,以帮助用户代理select合适的缩放algorithm。

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

像素化:

向上缩放图像时,必须使用“最近邻居”或类似的algorithm,以便图像看起来像是由很大的像素组成。 缩小时,这与自动相同。

标准? 跨浏览器?

由于这只是一个工作草案 ,所以不能保证这将成为标准。 浏览器的支持目前是多余的,充其量。

Mozilla开发者networking有一个非常全面的页面,致力于当前最先进的技术 ,我强烈推荐阅读。

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

更新:2014-09-12

Chrome 38现在支持image-rendering: pixelated

Firefox有一个打开的bug报告来获取image-rendering: pixelated实现,但是-moz-crisp-edges现在可以工作。

解?

到目前为止,最为跨平台的CSS解决scheme是:

 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中的高分辨率canvas表面上手动放大图像,甚至可以在服务器端进行缩放图像,但在我的情况下,这将会是非常昂贵的,因此它不是一个可行的选项。

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

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

现场演示

如果你想testing在MDN文章中讨论过的canvas元素的CSS属性,我已经做了这个小提琴 ,它应该显示这样的模糊或不模糊,取决于你的浏览器: 等距像素艺术风格电视的4:1(64x64至256x256)图像

新的答案2012年7月31日

这终于在canvas规格!

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

图像平滑最近才被添加到canvas规范中,并且不被所有浏览器支持,但是一些浏览器已经实现了该属性的供应商前缀版本。 在上下文中,Firefox和webkitImageSmoothingEnabled在Chrome和Safari中都存在,如果将它们设置为false,将会停止消除锯齿。 不幸的是,在写这篇文章的时候,IE9和Opera还没有实现这个属性,供应商是前缀的还是其他的。


预览: JSFiddle

结果:

在这里输入图像描述

编辑7/31/2012 – 此function现在在canvas规格! 在这里单独看答案:

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/

这创造了这个:

在这里输入图像描述

可能不是你想要的。 但是,如果你只是想要零模糊,那么这将是票,所以我会提供以防万一。

更困难的select是使用像素操作,并自己写一个algorithm的工作。 第一个图像的每个像素成为新图像上的5×5像素块。 imagedata不会太难。

但Canvas和CSS本身并不能帮助你将这个缩放到你想要的效果。

在谷歌浏览器,canvas图像模式不插值。

这是一个从namuol回答编辑的工作示例http://jsfiddle.net/pGs4f/

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

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图像呈现可以达到同样的效果:

  • Firefox 15.0.1 Mac OS X 10.6.8(图像渲染:-moz-crisp-edges在此工作 )
  • Opera 12.02 Mac OS X 10.6.8(图像渲染:-o-crisp-edges在此工作 )
  • Opera 12.02 Windows 7(图像渲染:-o-crisp-edges在此工作 )

有问题的是这些,因为ctx.XXXImageSmoothingEnabled不工作,图像渲染不工作:

  • Safari 5.1.7 Mac OS X 10.6.8。 (图像渲染:-webkit-optimize-contrast不起作用)
  • Safari 5.1.7 Windows 7(图像渲染:-webkit-optimize-contrast不起作用)
  • IE 9 Windows 7(-ms-interpolation-mode:最近邻居NOT工作)