25

I implemented a zoom in and out function on a canvas element. it works by scaling the canvas, translating it, and then redraw the whole scene again. the problem is that it takes a lot of time to redraw everything because i got a lot of things on my canvas.

I need a way to copy the canvas to an image object and than copy the image back to the canvas without loosing quality. what are the specific methods to copy canvas to a javascript variable, and to to copy this variable back to the canvas later?

I'll be glad if you write down the code because I couldn't find any good explanation over the internet.

thanks,

Amit Hagin
  • 3,136
  • 6
  • 26
  • 36
  • Do you want to restore the image zoomed, or as the size it originally was? – Loktar Aug 30 '11 at 12:38
  • No, the only way to 'retain quality' on a bitmap is to redraw. There's no magic way add extra pixels into the zoomed in bitmap without actually drawing those pixels. If you want to zoom in and out while retaining sharpness use SVG (vector) instead of Canvas (bitmap). – robertc Aug 31 '11 at 21:41
  • 1
    Ok, I've done performance tests for all the methods in the answers below. The drawImage() from another canvas seems to be the fastest: http://jsperf.com/canvas-image-store-restore – justGoscha Apr 16 '14 at 22:42

3 Answers3

31

The drawImage() method can draw to a canvas using another canvas instead of an image.

You could create a 'backup' canvas, of the same size as your original, draw the first one to there and then draw that one back to the original when you need it.

e.g.

// 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);
holem
  • 105
  • 1
  • 10
andrewmu
  • 14,276
  • 4
  • 39
  • 37
  • Is drawImage() called with Canvas as a parameter better than drawImage() called with an Image object as argument ? – Arun R Oct 17 '11 at 09:21
  • I imagine it would be quicker to call `drawImage()` with a canvas than to convert a canvas to a data URL, then load it into an Image, then call `drawImage()` with that image! – andrewmu Oct 17 '11 at 14:19
  • What if you need to store a lot of states in an array? Should one create an array of a bunch of canvases?? e.g. `var numBuffers = 20; var tmpCan = document.createElement('canvas'); var buffers = [tmpCan]; for (var i = 1, len = numBuffers, i < numBuffers; i++) { buffers.push(tmpCan.cloneNode()); }` or something like that?? **OR** is there a better solution? – dylnmc Jun 09 '17 at 17:30
  • @dylnmc - you could store an array of canvases but, for cases where you might be worried about the amount of memory used, you could export the image data, as Loktar's "Image in memory" answer shows. You should test to see if this is worthwhile for performance in your typical use case. – andrewmu Jun 15 '17 at 13:03
25

There are a few ways to do it theres the getImageData and putImageData methods Reference, However putImageData and getImageData are pretty slow. Another way is to save the data to an image in memory and recall it from that which is much faster, then the third way is the one above mentioned by andrewmu which involves copying to another canvas element. I have included examples for the first and second type.

Image in memory method

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 method

// 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);
}
Loktar
  • 34,764
  • 7
  • 90
  • 104
0

added image into canvas

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

holem
  • 105
  • 1
  • 10
zloctb
  • 10,592
  • 8
  • 70
  • 89
  • 1
    (1) op already has canvas populated; so, he/she doesn't need to know how to load an image into a canvas after it loads (2) op was asking how "convert" a canvas into an image, maintain a reference to that image and later on, restore the image to the canvas -- which, as others have pointed out -- is possible with toDataUrl() ==> img.src or using a temporary canvas. However, your answer doesn't really come close to answering the question. Maybe you could revise or remove, so as not to confuse people. – dylnmc Jun 09 '17 at 17:17
  • @zloctb Yeah you missunderstood the OP. It's not about how to simply show an image inside a canvas. – Thielicious Sep 02 '18 at 12:32