缩放<canvas>时禁用插值


126

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


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

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

该应用程序将是用HTML5 + JS编写的“复古” 8位样式游戏,以明确我的需求。


为了说明,这是一个示例。(现场版

假设我有一张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插值缩放后的画布元素 非插值版本


1
有点关系,虽然不完全相同:stackoverflow.com/questions/195262/...
HostileFork表示不信任SE

1
我认为这个问题是指绘制抗锯齿线条的线条绘制功能。我指的是默认情况下如何通过插值渲染调整大小的画布元素。
namuol 2011年

是的,很抱歉...我首先想到的是同样的问题,然后立即注意到我的错误。:-/如果您尝试使用jsmanipulate的像素化过滤器怎么办? joelb.me/jsmanipulate
HostileFork说不要相信SE SE

1
这更多的是用于照片的图像过滤器。
namuol 2011年

是的,但是如果它可以将您的左图像转换为右图像的足够好的版本以使您满意,那么它可以提供跨浏览器的解决方案(考虑到为这种绘图模式(通用或其他方式)寻找标记的可能性不大,在WebKit中)。是否可行的替代方法取决于您要解决的问题...如果您确实需要离散像素绘制,或者只是要确保结果以特定粒度像素化。
HostileFork说不要信任SE SE 2011年

Answers:


126

上次更新时间:2014-09-12

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

答案可能有一天。目前,您必须借助黑客手段来获得所需的东西。


image-rendering

CSS3的工作草案概述了一个新属性,image-rendering属性应该可以实现我想要的功能:

图像渲染属性向用户代理提供了有关在缩放图像时保留哪些方面最重要的提示,以帮助用户代理选择适当的缩放算法。

该规范概述接受三个值:autocrisp-edges,和pixelated

像素化:

在按比例放大图像时,必须使用“最近邻居”或类似算法,以便图像看起来仅由非常大的像素组成。缩小时,这与自动相同。

标准?跨浏览器?

由于这只是工作草案,因此无法保证这将成为标准。当前,对浏览器的支持充其量是最多的。

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文章中讨论的CSS属性的canvas元素,我做了这个小提琴应显示这样的事情,模糊或没有,这取决于你的浏览器: 等距像素艺术风格电视的4:1(64x64至256x256)图像


图像渲染似乎可以在其他地方使用,但是可以使用Webkit浏览器。我真的希望Chrome / Chromium / Safari工作人员能很好地理解“在低负载情况下切换到EPX插值”的含义。当我第一次读到了一句我以为优化对比度允许在低负荷创造了新的颜色,但NO:en.wikipedia.org/wiki/...
蒂莫Kähkönen

2
Mac和Windows上的Opera 12.02支持图像渲染:-o-crisp-edges(jsfiddle.net/VAXrL/21),因此您可以在答案中添加它。
TimoKähkönen'12 -10-8

当我增加浏览器缩放比例时,它应该可以工作吗?我已经在Windows 7上使用FF 22,Chrome 27和IE 10测试了绘图,当浏览器缩放为150%并且所有浏览器上的结果都模糊时。当我将画布的宽度和高度加倍,并使用CSS将其设置回原始宽度和高度时,它将绘制清晰的线条。
pablo

这是个好问题。我不确定是否有针对用户指定的缩放行为的规范。
namuol

1
我(从现在开始!)正在使用Chrome78。我看到的是“图像渲染:像素化;” 加工。看起来这是2015年添加到Chrome 41中的代码:developers.google.com/web/updates/2015/01/pixelated
MrColes

61

新答案7/31/2012

这终于在画布规格中!

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

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


预览:JSFiddle

结果:

在此处输入图片说明


1
不幸的是,这看起来还是行不​​通的。也许我想念什么?这是一个测试:jsfiddle.net/VAXrL/187
namuol

12
您必须使用canvas API进行缩放才能正常工作,无法使用CSS进行缩放,而使canvas API影响它!就像这样:jsfiddle.net/VAXrL/190
Simon Sarris

1
但是,这个问题的本质与画布无关。关于浏览器如何渲染缩放图像,包括<canvas>元素。
namuol 2012年

4
如果使用CSS进行缩放,则namuol的解决方案将起作用。如果将图像手动缩放到画布上,则Simon的解决方案有效。两种情况都有解决方案真是太好了,所以谢谢你们!
肖恩·勒布朗

对于IE 11:msImageSmoothingEnabled对我有用!msdn.microsoft.com/zh-CN/library/dn265062(v=vs.85).aspx
史蒂夫(Steve)

11

编辑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/

这创建了这个:

在此处输入图片说明

可能不是您想要的。但是,如果您只是想使模糊为零,那将是问题所在,因此我会以防万一。

一个更困难的选择是使用像素操纵并自己编写算法以完成工作。第一幅图像的每个像素变为新图像上的5x5像素块。使用imagedata并不难。

但是,仅Canvas和CSS并不能帮助您将一个缩放到另一个缩放并达到您想要的效果。


是的,那是我所担心的。显然,image-rendering: -webkit-optimize-contrast应该可以解决问题,但似乎什么也没做。我可能会考虑使用最近邻插值来滚动一个函数来缩放画布的内容。
namuol 2011年

我最初接受了您的回答;我暂时将其撤消,因为对于这是否是重复项似乎有些困惑。
namuol 2011年

经过研究后,我得到了更完整的答案,并希望重新打开问题以提供我的答案。
namuol 2011年

3

在谷歌浏览器中,不会插入画布图像图案。

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

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

这是到目前为止我所看到的最有吸引力的解决方法。尚不确定性能,但这完全值得研究。我会尝试一下。
namuol

使用重复而不是不重复更快。不知道为什么。它也非常快,Three.js在CanvasRenderer中使用了此功能
saviski

6
更新:不再适用于chrome 21(由于添加了视网膜显示支持?)新版本jsfiddle.net/saviski/pGs4f/12使用了Simon指出的
imageSmoothingEnabled

当视网膜分辨率普遍提高时,情况将发生巨大变化。当iPhone4-5风格的326dpi(128dpcm)Retina显示屏用于24英寸(52x32cm)显示器时,屏幕尺寸将为6656 x 4096像素。然后,抗锯齿是不好的,所有浏览器供应商(甚至是基于Webkit的厂商)都被迫允许禁用抗锯齿。抗锯齿是CPU密集型操作,抗锯齿6656 x 4096 px的图像速度太慢,但是幸运的是在这种显示器中没有必要。
TimoKähkönen2012年

1
只是一个旁注,这是一个很好的基准测试模式与图像的对比:jsperf.com/drawimage-vs-canvaspattern/9
yckart 2013年

1

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:nearest-neighbor无效)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.