注意:这与放大时如何渲染现有画布元素有关,与如何在画布表面上渲染线条或图形无关。换句话说,这与缩放元素的插值有关,与在画布上绘制的图形的抗锯齿无关。我不关心浏览器如何画线;我关心浏览器在放大时如何呈现画布元素本身。
缩放 <canvas>
元素时,是否可以通过编程方式更改画布属性或浏览器设置以禁用插值?跨浏览器解决方案是理想的,但不是必需的;基于 Webkit 的浏览器是我的主要目标。性能非常重要。
This question 最相似,但没有充分说明问题。对于它的价值,我尝试了 image-rendering: -webkit-optimize-contrast
无济于事。
该应用程序将是一个用 HTML5+JS 编写的“复古”8 位风格游戏,以明确我需要什么。
为了说明,这里有一个例子。 (live version)
假设我有一个 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) 渲染的。右边的图像是我想要的(为了说明目的手绘)。
https://i.stack.imgur.com/k72vO.png
最后更新:2014-09-12
是否有画布属性或浏览器设置我可以通过编程方式更改以在缩放元素时禁用插值?
答案也许有一天。现在,你必须求助于破解来获得你想要的东西。
图像渲染
The working draft of CSS3 outlines a new property, image-rendering
应该做我想做的事:
图像渲染属性向用户代理提供关于在缩放图像时最重要的图像的哪些方面的提示,以帮助用户代理选择适当的缩放算法。
该规范概述了三个可接受的值:auto
、crisp-edges
和 pixelated
。
像素化:放大图像时,必须使用“最近邻”或类似算法,使图像看起来只是由非常大的像素组成。缩小时,这与自动相同。
标准?跨浏览器?
由于这只是一个工作草案,因此不能保证这将成为标准。浏览器支持目前充其量是参差不齐的。
Mozilla 开发者网络有 a pretty thorough page dedicated to the current state of the art,我强烈建议您阅读。
Webkit 开发人员最初选择 tentatively implement this as -webkit-optimize-contrast
,但 Chromium/Chrome 似乎并未使用实现此功能的 Webkit 版本。
更新:2014-09-12
Chrome 38 now supports image-rendering: pixelated
!
Firefox 有一个 bug report 开放以实现 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,wrote a very in-depth article about this(他甚至最终在他的研究中引用了这个问题)。
有关依赖于 imageSmoothingEnabled
属性的基于画布的解决方案,请参阅 Simon's answer(在旧版浏览器中不可用,但比预缩放更简单且受到广泛支持)。
现场演示
https://i.stack.imgur.com/89AWQ.png
新答案 2012 年 7 月 31 日
这终于在画布规范中了!
该规范最近添加了一个名为 imageSmoothingEnabled
的属性,默认为 true
并确定在非整数坐标上绘制或按比例绘制的图像是否将使用更平滑的算法。如果将其设置为 false
,则使用最近邻,生成不太平滑的图像,而只是生成更大的像素。
图像平滑只是最近才添加到画布规范中,并非所有浏览器都支持,但一些浏览器已经实现了此属性的供应商前缀版本。在 Firefox 中存在 mozImageSmoothingEnabled
和 Chrome 和 Safari 中存在 webkitImageSmoothingEnabled
的上下文中,将它们设置为 false 将停止发生抗锯齿。不幸的是,在撰写本文时,IE9 和 Opera 还没有实现这个属性,无论是供应商前缀还是其他。
预览:JSFiddle
结果:
https://i.stack.imgur.com/sMa7m.png
编辑 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();
});
这创造了这个:
https://i.stack.imgur.com/YAQdz.png
可能不是你想要的。但是,如果您只是希望获得零模糊,那将是门票,所以我会提供它以防万一。
一个更困难的选择是使用像素操作并自己编写一个算法来完成这项工作。第一个图像的每个像素都成为新图像上的一个 5x5 像素块。使用图像数据不会太难。
但是,仅 Canvas 和 CSS 并不能帮助您在这里以您想要的确切效果缩放一个到另一个。
image-rendering: -webkit-optimize-contrast
应该可以解决问题,但似乎什么也没做。我可能会考虑滚动一个函数来使用最近邻插值来放大画布的内容。
在谷歌浏览器中,画布图像模式不会被插值。
这是从 namuol 答案 http://jsfiddle.net/pGs4f/ 编辑的工作示例
ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);
Saviski's workaround 说明 here 很有希望,因为它适用于:
铬 22.0.1229.79 Mac OS X 10.6.8
铬 22.0.1229.79 米 Windows 7
Chromium 18.0.1025.168(开发者内部版本 134367 Linux)Ubuntu 11.10
火狐 3.6.25 视窗 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:nearest-neighbor 不起作用)