CSS 缩放比绘图图像缩放更有效吗?



我想知道用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 的不同区域进行块状传输。我只交出整数来绘制图像,以保持尽可能清晰。我还有 CSS 画布上定义的image-rendering:pixelated和其他变体,用于 CSS 缩放以保持清晰。

我知道对于我的特定示例,我可以将 img 放大一次并围绕最终缩放的 img 进行平移,但这不是问题所在。问题是哪个性能更高。对于我的应用程序,我必须在每一帧上放大动画磁贴贴图,因此我将从多个源到1:1空间中的画布,然后使用requestAnimationFrame每秒将最终画布放大30到60次。

最后,它们给出了非常相似的结果。CSS与原始图像更加清晰和真实。CSS 更快/更高效吗?还是使用绘图图像进行缩放的性能更高?

注意/编辑:

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

Canvas Alpha 与众不同

为获得最佳效果,应保持画布大小与其分辨率相同。如果画布没有任何透明像素,则应关闭 Alpha。

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

缩放无关紧要

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

渲染的成本归结为绘制的像素数,而不是源中的像素数。

估算渲染成本

drawImage成本

如果画布分辨率为 200 x 200,并且您绘制了一个需要渲染的 40,000 像素的图像ctx.drawImage填充它。

合成成本

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

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

如果画布大小 (CSS( 与分辨率匹配且 Alpha 处于关闭状态,则无需为最终演示合成画布,并且不会产生额外的合成成本。

渲染成本示例

  • canvas是可见的画布元素
  • image是可以放入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

通过 CSS 和 alpha 关闭进行缩放

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 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 转换选项可能并非在所有浏览器上都可用。
  • 软件渲染和设备功能将对渲染性能产生最显著的影响。

最新更新