Javascript CSS缩放是否比drawImage缩放更有效?

Javascript CSS缩放是否比drawImage缩放更有效?,javascript,html5-canvas,scaling,css-transforms,drawimage,Javascript,Html5 Canvas,Scaling,Css Transforms,Drawimage,我想知道使用drawImage缩放与CSS之间的区别。我已经尝试了这两种方法,CSS似乎给出了稍微平滑的结果,而drawImage往往有点失真-特别是如果我平移图像,在几个动画帧的过程中从不同的源x和y进行闪烁。我在许多不同的尺度因子下测试后得出了这个结论。下面我有一个简单的例子 var img = new Image(); var ctx = document.querySelector("canvas").getContext("2d"); img.src = "img1000x1000.

我想知道使用
drawImage
缩放与CSS之间的区别。我已经尝试了这两种方法,CSS似乎给出了稍微平滑的结果,而
drawImage
往往有点失真-特别是如果我平移图像,在几个动画帧的过程中从不同的源x和y进行闪烁。我在许多不同的尺度因子下测试后得出了这个结论。下面我有一个简单的例子

var img = new Image();
var ctx = document.querySelector("canvas").getContext("2d");

img.src = "img1000x1000.png";// width and height are 1000

ctx.canvas.width  = 100;
ctx.canvas.height = 100;
ctx.imageSmoothingEnabled = false;
这将在img完全加载后运行

// method 1 uses drawImage to scale
ctx.drawImage(img, 0, 0, 100, 100, 0, 0, 200, 200);

// method 2 draws the img with no scaling and then uses css to scale
ctx.drawImage(img, 0, 0, 100, 100, 0, 0, 100, 100);
ctx.canvas.style.width  = 200;
ctx.canvas.style.height = 200;
请记住,我并不总是精确地缩放2倍的大小,我是从img的不同区域快速切换的。我只会将整数交给drawImage,以尽可能保持图像的清晰。我还有
图像渲染:像素化
和CSS中画布上定义的其他变体,用于CSS缩放以保持清晰

我知道对于我的具体例子,我可以放大一次img,然后围绕最终的img平移,但这不是问题所在。问题是哪一个更有效。对于我的应用程序,我必须在每一帧上放大一个动画平铺贴图,因此我将在1:1的空间中从多个源快速切换到画布,然后使用requestAnimationFrame每秒将最终画布放大30到60次

最后,他们给出了非常相似的结果。CSS几乎没有比原始图像更清晰和真实。CSS是否更快/更高效?或者使用drawImage进行缩放是否更有效

注/编辑:

我发现如果我使用标准模式和
,我必须将字符串值传递到CSS方法的
style.width
style.height
。因此,如果您使用的是标准模式,请确保将其设置为
“200px”
,而不仅仅是
200
,否则您的画布将无法缩放。

画布Alpha会起作用 为了获得最佳效果,应保持画布大小与其分辨率相同。如果画布没有任何透明像素,则应禁用alpha

使用
const ctx=canvas.getContext(“2d”,{alpha:false})关闭画布alpha

缩放是不相关的 对于大多数设备来说,缩放操作并不比绘制未缩放的图像更昂贵

渲染的成本取决于绘制的像素数,而不是源中的像素数

估计渲染成本
drawImage的成本
如果画布分辨率为200 x 200,并且您绘制了一幅填充它的图像
ctx.drawImage
,则需要渲染的像素数为40000

合成成本 如果通过CSS规则缩放画布,即使alpha处于禁用状态,也必须合成画布元素才能显示。成本将是画布大小占用的像素数

如果画布的alpha为true,则必须将其与背景合成,因此渲染成本是画布的显示大小(以像素为单位)

如果画布大小(CSS)与分辨率匹配,并且alpha处于禁用状态,则不需要为最终演示合成画布,也不需要额外的合成成本

渲染成本示例
  • canvas
    是一个可见的canvas元素
  • 图像
    是一种可以安装在GPU RAM中的图像
最好关闭alpha且无CSS缩放

canvas.width = canvas.height = 100;
canvas.style.width = canvas.style.height = "100px";
const ctx = canvas.getContext("2d", {alpha: false});
ctx.drawImage(image, 100, 100);

// Total rendering cost 100 * 100 = 10,000 pixels
canvas.width = canvas.height = 100;
canvas.style.width = canvas.style.height = "100px";
const ctx = canvas.getContext("2d");  // alpha is on
// same as const ctx = canvas.getContext("2d", {alpha: true});
ctx.drawImage(image, 100, 100);

// Total rendering cost 100 * 100 + 100 * 100 = 20,000 pixels
通过CSS和alpha off进行缩放

canvas.width = canvas.height = 200;
canvas.style.width = canvas.style.height = "100px";
const ctx = canvas.getContext("2d", {alpha: false});
ctx.drawImage(image, 200, 200);

// Total rendering cost 200 * 200 + 100 * 100 = 50,000 pixels
启用alpha渲染,无CSS缩放

canvas.width = canvas.height = 100;
canvas.style.width = canvas.style.height = "100px";
const ctx = canvas.getContext("2d", {alpha: false});
ctx.drawImage(image, 100, 100);

// Total rendering cost 100 * 100 = 10,000 pixels
canvas.width = canvas.height = 100;
canvas.style.width = canvas.style.height = "100px";
const ctx = canvas.getContext("2d");  // alpha is on
// same as const ctx = canvas.getContext("2d", {alpha: true});
ctx.drawImage(image, 100, 100);

// Total rendering cost 100 * 100 + 100 * 100 = 20,000 pixels
笔记
  • 由于页面设置、滚动和各种其他因素,呈现成本不可避免。这些成本被忽略,因为它们无法避免
  • 打开alpha的选项可能在所有浏览器上都不可用
  • 软件渲染和设备功能将对渲染性能产生最显著的影响

CSS会更快。我倾向于同意,但我没有证据。我想它是硬件加速的,就像CSS做的其他事情一样。这可能也是我会坚持的方法。然而,我在网上找不到任何速度比较或解释。我看到的三个主要选项是
ctx.drawImage
ctx.scale
,以及CSS样式。我还没有试过缩放。到目前为止,我只使用CSS,因为它看起来更干净,每帧只需要一次调用
drawImage
。似乎可以通过您可以创建和运行的测试来测量…@HereticMonkey,如果我找到答案,我会将其发布在这里,或者其他人可能会发布。无论哪种方式,它都会对其他有这个问题的人有用。这就是想法。所以,你要说的不是用哪个函数来合成,而是需要合成的图像的大小。这是有道理的。尽管如此,我还是情不自禁地注意到,CSS的实际扩展是不同的。实际上,与
drawImage
相比,它在放大时更干净。这使我相信使用了不同的算法。我确实关掉了alpha。我正在实施这里列出的所有技巧,其中之一是不要在每一帧上使用drawImage。@Frank Yes Chrome(我知道)在画布上使用不同的着色器。但是,您可以通过
ctx.imageSmoothingQuality
将质量设置更改为
“低”
(默认)
“中等”
,或
“高”
,这将在与
ctx.imageSmoothingEnabled=true
组合时更改缩放图像的采样方法,这是一个很好的提示。我几乎总是关闭imageSmoothing,但我肯定会再次查看CanvasRenderingContext2D规格,看看是否还有其他方法可以提高性能。@Frank为了获得最佳性能,您可以使用WebGL渲染2D内容。这有点复杂,但因为WebGL可以让您更好地组织状态更改(CPU和GPU之间的通信),所以您可以获得巨大的性能增益。例如普通笔记本电脑。。。2D上下文峰值为2000旋转缩放褪色透明精灵60Hz(2000状态更改)。WebGL批处理每个调用可处理256个精灵