HTML5:将画布复制到图像并返回

27
我在画布元素上实现了缩放功能,它通过缩放画布、平移并重新绘制整个场景来实现。问题在于由于我的画布上有很多东西,重新绘制需要花费很长时间。
我需要一种将画布复制到图像对象中,然后再将图像复制回画布而不失去质量的方法。具体的复制画布到 JavaScript 变量的方法是什么?如何将变量复制回画布?
如果您能提供代码,我会非常感激,因为我在网络上找不到任何好的说明。
谢谢。

您想恢复缩放后的图像,还是以原始大小显示? - Loktar
不,保留位图的质量的唯一方法是重新绘制。在放大的位图中添加额外像素的魔法方法不存在,必须实际绘制这些像素。如果您想要在保持锐度的同时缩放,请使用SVG(矢量)而不是Canvas(位图)。 - robertc
1
好的,我已经对下面所有答案中的方法进行了性能测试。从另一个画布中的drawImage()似乎是最快的: http://jsperf.com/canvas-image-store-restore - JustGoscha
3个回答

31

drawImage() 方法可以使用另一个画布而不是图像绘制到画布上。

您可以创建一个与原始画布相同大小的“备用”画布,将第一个画布绘制到该画布中,然后在需要时将该画布绘制回原始位置。

例如:

// Assume we have a main canvas
// canvas = <main canvas>
ctx = canvas.getContext('2d');

..

// create backing canvas
var backCanvas = document.createElement('canvas');
backCanvas.width = canvas.width;
backCanvas.height = canvas.height;
var backCtx = backCanvas.getContext('2d');

// save main canvas contents
backCtx.drawImage(canvas, 0,0);

..

// restore main canvas
ctx.drawImage(backCanvas, 0,0);

使用Canvas作为参数调用drawImage()比使用Image对象作为参数调用drawImage()更好吗? - Arun R
我想使用画布调用drawImage()会比将画布转换为数据URL,然后将其加载到图像中,再使用该图像调用drawImage()更快! - andrewmu
如果您需要在数组中存储大量状态,该怎么办?应该创建一堆画布的数组吗?例如:var numBuffers = 20; var tmpCan = document.createElement('canvas'); var buffers = [tmpCan]; for (var i = 1, len = numBuffers, i < numBuffers; i++) { buffers.push(tmpCan.cloneNode()); }或者类似这样的东西?还是有更好的解决方案吗? - dylnmc
@dylnmc - 你可以存储一个画布数组,但是如果你担心使用的内存量,你可以像Loktar的“内存中的图像”答案所示,导出图像数据。你应该测试一下,在你的典型用例中,这是否值得为了性能考虑。 - andrewmu

26

有几种方法可以做到这一点,其中包括 getImageDataputImageData 方法(参考)。 然而,putImageDatagetImageData 的速度较慢。另一种方法是将数据保存到内存中的 image 并从中调用它,这样更快。 第三种方式是由andrewmu提到的涉及复制到另一个画布元素的方式。我已经为第一种和第二种类型包含了示例。

内存中的图像方法

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    savedData = new Image();

function save(){
    // get the data
    savedData.src = canvas.toDataURL("image/png");
}

function restore(){
    // restore the old canvas
    ctx.drawImage(savedData,0,0)
}

getImageData putImageData方法

// Setup our vars, make a new image to store the canvas data
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    canvasData = '';

function save(){
    // get the data
    canvasData = ctx.getImageData(0, 0, 100, 100);
}

function restore(){
    // restore the old canvas
    ctx.putImageData(canvasData, 0, 0);
}

有人对这个进行了JS性能测试吗? :D - JustGoscha
@JustGoscha 嗯,不确定。我想如果有人有的话,那就是 Simon Sarris。 - Loktar
1
谢谢,这个答案帮了我很多。我发现get/put方法是同步运行的,而“内存中方法”是异步运行的。 - david webber

0

图像添加到画布

var image = new Image();
image.src = "1.jpg";
image.onload = function () {
  context.drawImage(image, 0, 0);
};


1
(1)op已经有画布了,所以他/她不需要知道如何在画布加载后将图像加载到画布中。(2)op正在询问如何将画布“转换”为图像,保留对该图像的引用,并在以后将图像恢复到画布中-正如其他人指出的那样-可以使用toDataUrl() ==> img.src或使用临时画布。但是,您的答案实际上并没有接近回答问题。也许您可以修改或删除,以免混淆人们。 - dylnmc
@zloctb,你误解了OP的意思。这不是关于如何简单地在画布内显示图像的问题。 - Thielicious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接