ChatGPT解决这个技术问题 Extra ChatGPT

缩放 <canvas> 时禁用插值

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

缩放 <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

有些相关,但不相同:stackoverflow.com/questions/195262/…
我相信这个问题是指绘制抗锯齿线的画线功能。我指的是默认情况下如何使用插值渲染调整大小的画布元素。
是的,对不起......我首先认为问题相同,然后立即注意到我的错误。 :-/ 如果您尝试使用 jsmanipulate 的像素化过滤器会怎样? joelb.me/jsmanipulate
这更像是用于照片的图像过滤器。
是的,但是如果它将您的左图像转换为右图像的一个足够好的版本以使您开心,那么它可以提供跨浏览器解决方案(考虑到为这种绘图模式找到一个标志看起来不太有希望,通用或其他,在 WebKit 中)。它是否是可行的替代品取决于您要解决的问题……如果您真的需要离散像素绘图,或者您只是想确保结果以一定的粒度进行像素化。

C
Community

最后更新:2014-09-12

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

答案也许有一天。现在,你必须求助于破解来获得你想要的东西。

图像渲染

The working draft of CSS3 outlines a new property, image-rendering 应该做我想做的事:

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

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

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

标准?跨浏览器?

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

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


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

新答案 2012 年 7 月 31 日

这终于在画布规范中了!

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

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

预览:JSFiddle

结果:

https://i.stack.imgur.com/sMa7m.png


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

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

这创造了这个:

https://i.stack.imgur.com/YAQdz.png

可能不是你想要的。但是,如果您只是希望获得零模糊,那将是门票,所以我会提供它以防万一。

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

但是,仅 Canvas 和 CSS 并不能帮助您在这里以您想要的确切效果缩放一个到另一个。


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

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

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

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

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

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 不起作用)