Javascript 缩放 <canvas> 时禁用插值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7615009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:54:53  来源:igfitidea点击:

Disable Interpolation when Scaling a <canvas>

javascripthtmlcanvas

提问by namuol

NOTE: This has to do with how existing canvas elements are rendered when scaled up, notto do with how lines or graphics are rendered onto a canvas surface. In other words, this has everything to do with interpolationof scaled elements, and nothing to do with antialiasingof graphics being drawn on a canvas. I'm not concerned with how the browser draws lines; I care about how the browser renders the canvas element itselfwhen it is scaled up.

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



Is there a canvas property or browser setting I can change programmatically to disable interpolation when scaling <canvas>elements? A cross-browser solution is ideal but not essential; Webkit-based browsers are my main target. Performance is very important.

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

This questionis most similar but does not illustrate the problem sufficiently. For what it's worth, I have tried image-rendering: -webkit-optimize-contrastto no avail.

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

The application will be a "retro" 8-bit styled game written in HTML5+JS to make it clear what I need.

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



To illustrate, here is an example. (live version)

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

Suppose I have a 21x21 canvas...

假设我有一个 21x21 的画布...

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

...which has css that makes the element 5 times larger (105x105):

...具有使元素大 5 倍 (105x105) 的 css:

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

I draw a simple 'X' on the canvas like so:

我在画布上画了一个简单的“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();
});

The image on the left is what Chromium (14.0) renders. The image on the right is what I want (hand-drawn for illustrative purposes).

左边的图像是 Chromium (14.0) 渲染的。右边的图像是我想要的(手绘用于说明目的)。

Chrome interpolates scaled canvas elementsA non-interpolated version

Chrome 插入缩放的画布元素非插值版本

采纳答案by namuol

Last Updated: 2014-09-12

最后更新:2014-09-12

Is there a canvas property or browser setting I can change programmatically to disable interpolation when scaling elements?

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

The answer is maybe some day. For now, you'll have to resort to hack-arounds to get what you want.

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



image-rendering

image-rendering

The working draft of CSS3 outlines a new property, image-renderingthat should do what I want:

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

The image-rendering property provides a hint to the user-agent about what aspects of an image are most important to preserve when the image is scaled, to aid the user-agent in the choice of an appropriate scaling algorithm.

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

The specification outlines three accepted values: auto, crisp-edges, and pixelated.

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

pixelated:

When scaling the image up, the "nearest neighbor" or similar algorithm must be used, so that the image appears to be simply composed of very large pixels. When scaling down, this is the same as auto.

像素化:

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

Standard? Cross-browser?

标准?跨浏览器?

Since this is merely a working draft, there's no guarantee that this will become standard. Browser support is currently spotty, at best.

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

The Mozilla Developer Network has a pretty thorough page dedicated to the current state of the artwhich I highly recommend reading.

Mozilla 开发人员网络有一个非常详尽的页面,专门介绍当前最先进的技术,我强烈推荐阅读。

The Webkit developers initially chose to tentatively implement this as -webkit-optimize-contrast, but Chromium/Chrome don't seem to be using a version of Webkit that implements this.

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

Update: 2014-09-12

更新:2014-09-12

Chrome 38 now supports image-rendering: pixelated!

Chrome 38 现在支持image-rendering: pixelated

Firefox has a bug reportopen to get image-rendering: pixelatedimplemented, but -moz-crisp-edgesworks for now.

Firefox 有一个错误报告可供image-rendering: pixelated实施,但-moz-crisp-edges现在可以使用。

Solution?

解决方案?

The most cross-platform, CSS-only solution so far is thus:

迄今为止,最跨平台、仅使用 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                            */
}

Sadly this wont work on all major HTML5 platforms yet (Chrome, in particular).

遗憾的是,这还不适用于所有主要的 HTML5 平台(尤其是 Chrome)。

Of course, one could manually scale up images using nearest-neighbor interpolation onto high-resolution canvas surfaces in javascript, or even pre-scale images server-side, but in my case this will be forbiddingly costly so it is not a viable option.

当然,人们可以在 javascript 中使用最近邻插值手动将图像放大到高分辨率画布表面,甚至可以在服务器端预先缩放图像,但在我的情况下,这将是非常昂贵的,因此它不是一个可行的选择。

ImpactJSuses a texture pre-scaling technique to get around all this FUD. Impact's developer, Dominic Szablewski, wrote a very in-depth article about this(he even ended up citing this question in his research).

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

See Simon's answerfor a canvas-based solution that relies on the imageSmoothingEnabledproperty (not available in older browsers, but simpler than pre-scaling and pretty widely-supported).

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

Live Demo

现场演示

If you'd like to test the CSS properties discussed in the MDN article on canvaselements, I've made this fiddlewhich should display something like this, blurry or not, depending on your browser: a 4:1 (64x64 to 256x256) image of an isometric pixel-art style TV

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

回答by Simon Sarris

New answer 7/31/2012

新答案 7/31/2012

This is finally in the canvas spec!

这终于在画布规范中了!

The specification has recently added a property called imageSmoothingEnabled, which defaults to trueand determines if images drawn on non-integer coordinates or drawn scaled will use a smoother algorithm. If it is set to falsethen nearest-neighbor is used, producing a less smooth image and instead just making larger looking pixels.

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

Image smoothing has only recently been added to the canvas specification and isn't supported by all browsers, but some browsers have implemented vendor-prefixed versions of this property. On the context there exists mozImageSmoothingEnabledin Firefox and webkitImageSmoothingEnabledin Chrome and Safari, and setting these to false will stop anti-aliasing from occurring. Unfortunately, at the time of writing, IE9 and Opera have not implemented this property, vendor prefixed or otherwise.

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



Preview: JSFiddle

预览:JSFiddle

Result:

结果:

enter image description here

在此处输入图片说明

回答by Simon Sarris

Edit 7/31/2012 - This functionality is now in the canvas spec! See separate answer here:

2012 年 7 月 31 日编辑 - 此功能现在在画布规范中!在此处查看单独的答案:

https://stackoverflow.com/a/11751817/154112

https://stackoverflow.com/a/11751817/154112

Old answer is below for posterity.

旧答案如下供后代使用。



Depending on your desired effect, you have this as one option:

根据您想要的效果,您可以将其作为一种选择:

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/

http://jsfiddle.net/wa95p/

Which creates this:

这创造了这个:

enter image description here

在此处输入图片说明

Probably not what you want. But if you were merely looking to have zero blur then that would be the ticket so I'll offer it just in case.

可能不是你想要的。但是,如果您只是希望实现零模糊,那么这就是票,所以我会提供它以防万一。

A more difficult option is to use pixel manipulation and write an algorithm yourself for the job. Each pixel of the first image becomes a 5x5 block of pixels on the new image. It wouldn't be too hard to do with imagedata.

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

But Canvas and CSS alone won't help you here for scaling one to the other with the exact effect you desire.

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

回答by saviski

In google chrome, canvas image patterns aren't interpolated.

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

Here is a working example edited from the namuol answer http://jsfiddle.net/pGs4f/

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

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

回答by Timo K?hk?nen

Saviski's workaroundexplicated hereis promising, because it works on:

此处说明的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
  • 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

But not works in the following, but the same effect can be achieved using CSS image-rendering:

但在以下情况下不起作用,但使用 CSS 图像渲染可以实现相同的效果:

  • Firefox 15.0.1 Mac OS X 10.6.8 (image-rendering:-moz-crisp-edges works in this)
  • Opera 12.02 Mac OS X 10.6.8 (image-rendering:-o-crisp-edges works in this)
  • Opera 12.02 Windows 7 (image-rendering:-o-crisp-edges works in this)
  • 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 在此有效

The problematic are these, because ctx.XXXImageSmoothingEnabled is not working and image-rendering is not working:

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

  • Safari 5.1.7 Mac OS X 10.6.8. (image-rendering:-webkit-optimize-contrast NOT works)
  • Safari 5.1.7 Windows 7 (image-rendering:-webkit-optimize-contrast NOT works)
  • IE 9 Windows 7 (-ms-interpolation-mode:nearest-neighbor NOT works)
  • 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 不工作)