缩放 <canvas> 时禁用插值

IT技术 javascript html canvas
2021-01-30 00:43:29

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


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

这个问题最相似,但没有充分说明问题。对于它的value,我试图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 插入缩放的画布元素 非插值版本

5个回答

最后更新:2014-09-12

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

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


image-rendering

CSS3 的工作草案概述了一个新属性,image-rendering它应该可以满足我的要求:

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

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

像素化:

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

标准?跨浏览器?

由于这只是一个工作草案,不能保证这会成为标准。浏览器支持目前充其量是参差不齐的。

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属性的基于画布的解决方案(在较旧的浏览器中不可用,但比预缩放更简单且得到广泛支持)。

现场演示

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

我(来自现在的未来!)在 Chrome 78 上。我看到“图像渲染:像素化;” 在职的。看起来这是在 2015 年添加到 Chrome 41:developers.google.com/web/updates/2015/01/pixelated
2021-03-23 00:43:29
图像渲染似乎在其他地方工作,但 webkit 浏览器。我真的希望 Chrome/Chromium/Safari 工作人员能很好地理解“在低负载情况下切换到 EPX 插值”的含义。当我第一次阅读这句话时,我认为优化对比度允许在低负载下创建新颜色,但不是:en.wikipedia.org/wiki/...
2021-03-30 00:43:29
这是个好问题。我不确定是否有针对用户指定的缩放行为的规范。
2021-03-31 00:43:29
当我增加浏览器缩放时它应该工作吗?我已经在 Windows 7 上使用 FF 22、Chrome 27 和 IE 10 测试过,当浏览器缩放为 150% 时,结果在所有浏览器上都很模糊。当我将画布宽度和高度加倍并使用 CSS 将其设置回原始宽度和高度时,它会绘制清晰的线条。
2021-04-02 00:43:29
Mac 和 Windows 上的 Opera 12.02 支持图像渲染:-o-crisp-edges ( jsfiddle.net/VAXrL/21 ),因此您可以将其添加到您的答案中。
2021-04-06 00:43:29

新答案 7/31/2012

这终于在画布规范中了!

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

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


预览:JSFiddle

结果:

在此处输入图片说明

如果您使用 CSS 进行缩放,namuol 的解决方案将起作用。如果您手动将图像缩放到 Canvas 上,Simon 的解决方案会起作用。很高兴这两种情况都有解决方案,所以谢谢你们!
2021-03-14 00:43:29
对于 IE 11:msImageSmoothingEnabled 对我有用!msdn.microsoft.com/en-us/library/dn265062(v=vs.85).aspx
2021-03-14 00:43:29
您必须使用画布 API 进行缩放才能使其工作,您永远无法使用 CSS 进行缩放并让画布 API 影响它!所以像这样:jsfiddle.net/VAXrL/190
2021-03-26 00:43:29
不幸的是,这看起来也不起作用。也许我错过了什么?这是一个测试:jsfiddle.net/VAXrL/187
2021-04-07 00:43:29
但是这个问题的本质并不是关于画布。它是关于浏览器如何呈现缩放图像,包括 <canvas> 元素。
2021-04-11 00:43:29

编辑 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 像素块。使用图像数据不会太难。

但是,单靠 Canvas 和 CSS 并不能帮助您以您想要的确切效果将一个缩放到另一个。

做了一些研究后,我有了更完整的答案,并想重新打开问题以提供我的答案。
2021-03-16 00:43:29
是的,这就是我害怕的。显然,image-rendering: -webkit-optimize-contrast应该可以解决问题,但似乎什么也没做。我可能会考虑滚动一个函数来使用最近邻插值来放大画布的内容。
2021-03-27 00:43:29
我最初接受了您的回答;我暂时撤销了它,因为似乎对这是否重复存在混淆。
2021-03-29 00:43:29

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

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

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);
当 Retina 分辨率普遍化时,情况会发生巨大变化。当 iPhone4-5 风格的 326dpi (128dpcm) Retina 显示器出现在 24 英寸 (52x32cm) 显示器上时,屏幕尺寸将为 6656 x 4096 像素。然后抗锯齿很糟糕,所有浏览器供应商(甚至基于 Webkit 的)都被迫允许禁用抗锯齿。抗锯齿是 CPU 密集型操作,抗锯齿 6656 x 4096 像素图像会太慢,但幸运的是在这种显示中没有必要。
2021-03-19 00:43:29
顺便提一下,这里有一个关于模式与图像的很好的基准测试:jsperf.com/drawimage-vs-canvaspattern/9
2021-03-25 00:43:29
使用重复而不是不重复更快。不知道为什么。它也相当快,three.js 在 CanvasRenderer 中使用它
2021-04-07 00:43:29
这是迄今为止我见过的最有吸引力的解决方法。还不确定性能,但完全值得研究。我会尝试一下。
2021-04-08 00:43:29
更新:不再适用于 chrome 21(由于添加了视网膜显示支持?)新版本jsfiddle.net/saviski/pGs4f/12使用由 Simon 指出的 imageSmoothingEnabled
2021-04-11 00:43:29

此处说明的Saviski 解决方法很有前景,因为它适用于:

  • Chrome 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 不工作)