73

Is there any way to create a deep copy of a canvas element with all drawn content?

dakab
  • 5,379
  • 9
  • 43
  • 67
Evgenyt
  • 10,201
  • 12
  • 40
  • 44

2 Answers2

141

Actually the correct way to copy the canvas data is to pass the old canvas to the new blank canvas. Try this function.

function cloneCanvas(oldCanvas) {

    //create a new canvas
    var newCanvas = document.createElement('canvas');
    var context = newCanvas.getContext('2d');

    //set dimensions
    newCanvas.width = oldCanvas.width;
    newCanvas.height = oldCanvas.height;

    //apply the old canvas to the new one
    context.drawImage(oldCanvas, 0, 0);

    //return the new canvas
    return newCanvas;
}

Using getImageData is for pixel data access, not for copying canvases. Copying with it is very slow and hard on the browser. It should be avoided.

Robert Hurst
  • 8,902
  • 5
  • 42
  • 66
  • 5
    +1 on the `drawImage()` reference, but it's worth noting the call to `new Canvas()` does not work in all browsers (notably Firefox) - instead you should use `document.createElement('canvas')` – AJ. Mar 02 '12 at 16:26
  • pretty strange error here: when loading an image and adjusting the canvas' size accordingly and _then_ cloning it, it does only clone the first 300px (horizontally) and the first 150px (vertically) (see http://peter.muehlbacher.me/playground/mycelium?src=../downloads/chess_pawn.png console when clicking around - it's logging the alpha values of the copy) – Peter Sep 22 '12 at 21:45
  • 3
    ok found the error: you need to set `newCanvas.width = oldCanvas.width; newCanvas.height = oldCanvas.height;` before calling the `drawImage()` function. – Peter Sep 23 '12 at 12:25
  • 1
    Yea, changing the dimensions of a canvas discards the image data. – Robert Hurst Sep 25 '12 at 06:16
  • Is there a way that I can clone what I have from one canvas to another as I draw in the first canvas? Like simultaneously – Glund Jul 24 '14 at 13:18
  • @RobertHurst, it looks like you're not using `getImageData` anymore, is that correct? – trysis Aug 11 '15 at 19:42
  • 1
    @trysis That right, it isn't necessary to use `getImageData` when unless you need access to the raw data, like if you want to dump the data somewhere or something. It's much faster to let the drawImage method to do the work. – Robert Hurst Aug 11 '15 at 20:44
  • Got it. Sorry, it looked like there was a typo there, but I must need new glasses. – trysis Aug 12 '15 at 01:24
  • Why not `canvas.toBlob()` or `canvas.toDataURL()`? – Lee Goddard Sep 19 '18 at 01:26
  • @RobertHurst Does this method also clone its associated javascript? For example, if the canvas has a clickable area, with some defined behavior, would that feature also be copied over, or does this only treat the canvas to be copied as a static image? – ajfbiw.s Sep 20 '18 at 21:43
13

You can call

context.getImageData(0, 0, context.canvas.width, context.canvas.height);

which will return an ImageData object. This has a property named data of type CanvasPixelArray which contains the rgb and transparency values of all the pixels. These values are not references to the canvas so can be changed without affecting the canvas.

If you also want a copy of the element, you could create a new canvas element and then copy all attributes to the new canvas element. After that you can use the

context.putImageData(imageData, 0, 0);

method to draw the ImageData object onto the new canvas element.

See this answer for more detail getPixel from HTML Canvas? on manipulating the pixels.

You might find this mozilla article useful as well https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes

Community
  • 1
  • 1
Castrohenge
  • 8,525
  • 5
  • 39
  • 66