缩放<canvas>时禁用插值

nam*_*uol 121 javascript html5 canvas

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


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

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

该应用程序将是一个用HTML5 + JS编写的"复古"8位风格的游戏,以明确我需要的东西.


为了说明,这是一个例子.(现场版)

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

<canvas id='b' width='21' height='21'></canvas>
Run Code Online (Sandbox Code Playgroud)

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

canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */
Run Code Online (Sandbox Code Playgroud)

我在画布上绘制一个简单的'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();
});
Run Code Online (Sandbox Code Playgroud)

左边的图像是Chromium(14.0)渲染的图像.右边的图像是我想要的(手绘为了说明目的).

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

nam*_*uol 120

最后更新时间:2014-09-12

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

答案可能某一天.现在,你将不得不诉诸黑客来获得你想要的东西.


image-rendering

CSS3的工作草案概述了一个新属性,image-rendering它应该做我想要的:

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

该规范概述接受三个值:auto,crisp-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                            */
}
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这还不适用于所有主要的HTML5平台(特别是Chrome).

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

ImpactJS使用纹理预缩放技术来绕过所有这些FUD.Impact的开发人员Dominic Szablewski 撰写了一篇非常深入的文章(他甚至最终在他的研究中引用了这个问题).

请参阅Simon对基于画布的解决方案的回答,该解决方案依赖于该imageSmoothingEnabled属性(在旧版浏览器中不可用,但比预缩放和相当广泛支持的简单).

现场演示

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

  • 我(来自现在的未来!)使用 Chrome 78。我看到“图像渲染:像素化;” 在职的。看起来这是在 2015 年添加到 Chrome 41 中的:https://developers.google.com/web/updates/2015/01/pixelated (3认同)
  • 在Mac和Windows歌剧院12.02支持图像渲染:-o-清脆的边缘(http://jsfiddle.net/VAXrL/21/),所以你可以添加在你的答案. (2认同)

Sim*_*ris 59

新答案7/31/2012

这最终是在画布规格!

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

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


预览:JSFiddle

结果:

在此输入图像描述

  • 你必须使用canvas API进行扩展才能工作,你无法使用CSS进行扩展并且使用canvas API来影响它!所以像这样:http://jsfiddle.net/VAXrL/190/ (12认同)
  • 如果使用CSS扩展,namuol的解决方案将起作用.如果您手动将图像缩放到Canvas上,Simon的解决方案可以正常工作.这两种情况都有解决方案,这很好,谢谢你们俩! (4认同)

Sim*_*ris 11

编辑7/31/2012 - 此功能现在在画布规范中!请在此处单独回答:

/sf/answers/822627221/

后代的答案如下.


根据您所需的效果,您可以选择以下选项:

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();
});
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/wa95p/

这创造了这个:

在此输入图像描述

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

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

但Canvas和CSS本身并没有帮助你将一个缩放到另一个具有你想要的确切效果.