修改后重置canvas为上一张图片
Reset canvas to previous picture after modifications
假设我有一个简单的 canvas 元素,并在其上绘制复杂的资源密集型图片。然后我在图片上画了一些简单的线条。有没有办法 "save" canvas 的状态(在绘制线条之前),然后重新绘制状态以擦除所做的任何进一步更改。我确实用 save()
和 restore()
尝试过,但我认为它的状态不包括 canvas 上的当前形状。请参阅下面的演示。
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
function init() {
// This is some computationally intensive drawing we don't want to repeat
context.fillStyle = "rgb(150,29,28)";
context.fillRect(40, 40, 255, 200);
context.fillStyle = "rgb(150,83,28)";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgb(17,90,90)";
context.fillRect(5, 100, 200, 120);
context.fillStyle = "rgb(22,120,22)";
context.fillRect(200, 200, 90, 90);
// Now we save the state so we can return to it
saveState();
}
function lines() {
// This is some drawing we will do and then want to get rid of
context.beginPath();
context.moveTo(125, 125);
context.lineTo(150, 45);
context.lineTo(200, 200);
context.closePath();
context.stroke();
}
function saveState() {
//copy the data into some variable
}
function loadState() {
//load the data from the variable and apply to canvas
}
init();
#canvas {
border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>
您可以创建一个 <img>
元素,调用 canvas.toDataURL()
将原始 canvas
存储在 saveState(), use
context.clearRect()to clear
canvas,
context.drawImage()to restore saved
canvas`
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var _canvas;
var img = new Image;
img.width = canvas.width;
img.height = canvas.height;
function init() {
// This is some computationally intensive drawing we don't want to repeat
context.fillStyle = "rgb(150,29,28)";
context.fillRect(40, 40, 255, 200);
context.fillStyle = "rgb(150,83,28)";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgb(17,90,90)";
context.fillRect(5, 100, 200, 120);
context.fillStyle = "rgb(22,120,22)";
context.fillRect(200, 200, 90, 90);
// Now we save the state so we can return to it
saveState(canvas);
}
function lines() {
// This is some drawing we will do and then want to get rid of
context.beginPath();
context.moveTo(125, 125);
context.lineTo(150, 45);
context.lineTo(200, 200);
context.closePath();
context.stroke();
}
function saveState(c) {
_canvas = c.toDataURL();
//copy the data into some variable
}
function loadState() {
//load the data from the variable and apply to canvas
context.clearRect(0, 0, canvas.width, canvas.height);
img.onload = function() {
context.drawImage(img, 0, 0);
}
img.src = _canvas;
}
init();
#canvas {
border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>
您只需将 canvas 复制到新的即可。
// canvas is the canvas you want to copy.
var canvasBack = document.createElement("canvas");
canvasBack.width = canvas.width;
canvasBack.height = canvas.height;
canvasBack.ctx = canvasBack.getContext("2d");
canvasBack.ctx.drawImage(canvas,0,0);
您将新的 canvas 视为另一张图像,可以使用
将其复制到原始图像
ctx.drawImage(canvasBack,0,0);
渲染图像是在硬件中完成的,因此可以很容易地实时完成每帧多次。因此,您可以将 canvases 视为图层(如 photoshop)并使用 globalCompositeOperation 创建范围广泛的可调 FX。
您可以转换为 dataURL,但这个过程要慢得多,而且对于实时呈现来说还不够快。此外,保留 DataURL 字符串的副本然后将其解码为图像将比仅创建 canvas 副本(base64 在每 4 个字符中编码 3 个字节(24 位))对内存造成更大的压力。由于 JS 字符为 16 bits long 在 base64 中存储数据效率非常低(64 位内存用于存储 24 位)
另一种方法是将 canvas 存储为带有 ctx.getImageData 的类型化数组,但这也很慢,无法满足实时需求。
假设我有一个简单的 canvas 元素,并在其上绘制复杂的资源密集型图片。然后我在图片上画了一些简单的线条。有没有办法 "save" canvas 的状态(在绘制线条之前),然后重新绘制状态以擦除所做的任何进一步更改。我确实用 save()
和 restore()
尝试过,但我认为它的状态不包括 canvas 上的当前形状。请参阅下面的演示。
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
function init() {
// This is some computationally intensive drawing we don't want to repeat
context.fillStyle = "rgb(150,29,28)";
context.fillRect(40, 40, 255, 200);
context.fillStyle = "rgb(150,83,28)";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgb(17,90,90)";
context.fillRect(5, 100, 200, 120);
context.fillStyle = "rgb(22,120,22)";
context.fillRect(200, 200, 90, 90);
// Now we save the state so we can return to it
saveState();
}
function lines() {
// This is some drawing we will do and then want to get rid of
context.beginPath();
context.moveTo(125, 125);
context.lineTo(150, 45);
context.lineTo(200, 200);
context.closePath();
context.stroke();
}
function saveState() {
//copy the data into some variable
}
function loadState() {
//load the data from the variable and apply to canvas
}
init();
#canvas {
border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>
您可以创建一个 <img>
元素,调用 canvas.toDataURL()
将原始 canvas
存储在 saveState(), use
context.clearRect()to clear
canvas,
context.drawImage()to restore saved
canvas`
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var _canvas;
var img = new Image;
img.width = canvas.width;
img.height = canvas.height;
function init() {
// This is some computationally intensive drawing we don't want to repeat
context.fillStyle = "rgb(150,29,28)";
context.fillRect(40, 40, 255, 200);
context.fillStyle = "rgb(150,83,28)";
context.fillRect(10, 10, 50, 50);
context.fillStyle = "rgb(17,90,90)";
context.fillRect(5, 100, 200, 120);
context.fillStyle = "rgb(22,120,22)";
context.fillRect(200, 200, 90, 90);
// Now we save the state so we can return to it
saveState(canvas);
}
function lines() {
// This is some drawing we will do and then want to get rid of
context.beginPath();
context.moveTo(125, 125);
context.lineTo(150, 45);
context.lineTo(200, 200);
context.closePath();
context.stroke();
}
function saveState(c) {
_canvas = c.toDataURL();
//copy the data into some variable
}
function loadState() {
//load the data from the variable and apply to canvas
context.clearRect(0, 0, canvas.width, canvas.height);
img.onload = function() {
context.drawImage(img, 0, 0);
}
img.src = _canvas;
}
init();
#canvas {
border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>
您只需将 canvas 复制到新的即可。
// canvas is the canvas you want to copy.
var canvasBack = document.createElement("canvas");
canvasBack.width = canvas.width;
canvasBack.height = canvas.height;
canvasBack.ctx = canvasBack.getContext("2d");
canvasBack.ctx.drawImage(canvas,0,0);
您将新的 canvas 视为另一张图像,可以使用
将其复制到原始图像ctx.drawImage(canvasBack,0,0);
渲染图像是在硬件中完成的,因此可以很容易地实时完成每帧多次。因此,您可以将 canvases 视为图层(如 photoshop)并使用 globalCompositeOperation 创建范围广泛的可调 FX。
您可以转换为 dataURL,但这个过程要慢得多,而且对于实时呈现来说还不够快。此外,保留 DataURL 字符串的副本然后将其解码为图像将比仅创建 canvas 副本(base64 在每 4 个字符中编码 3 个字节(24 位))对内存造成更大的压力。由于 JS 字符为 16 bits long 在 base64 中存储数据效率非常低(64 位内存用于存储 24 位)
另一种方法是将 canvas 存储为带有 ctx.getImageData 的类型化数组,但这也很慢,无法满足实时需求。