14

This is working, but I feel this code is lengthy. I'm looking for better idea.

var clone = function(imageData) {
  var canvas, context;
  canvas = document.createElement('canvas');
  canvas.width = imageData.width;
  canvas.height = imageData.height;
  context = canvas.getContext('2d');
  context.putImageData(imageData, 0, 0);
  return context.getImageData(0, 0, imageData.width, imageData.height);
};
ashleedawg
  • 20,365
  • 9
  • 72
  • 105
minodisk
  • 650
  • 6
  • 18
  • 1
    Possible duplicate of [Copy imageData by value in JavaScript](http://stackoverflow.com/questions/5642383/copy-imagedata-by-value-in-javascript) – brichins Jun 13 '16 at 20:07

3 Answers3

17

The ImageData constructor accepts the image data array.

const imageDataCopy = new ImageData(
  new Uint8ClampedArray(imageData.data),
  imageData.width,
  imageData.height
)
markbrown4
  • 393
  • 3
  • 9
  • 2
    For those wondering, like me, no, `ImageData` constructor doesn't clone the `array` argument, and uses it as its data, so `new Uint8ClampedArray` is necessary. [Source.](https://html.spec.whatwg.org/multipage/canvas.html#dom-imagedata) – Alec Mev Sep 27 '18 at 18:11
12

With TypedArray.prototype.set() you can directly copy the data.

var imageDataCopy = new Uint8ClampedArray(originalImageData.data);
imageDataCopy.set(originalImageData.data);

This sets the content of imageDataCopy to be identical to originalImageData.

TLJ
  • 4,525
  • 2
  • 31
  • 46
ueni
  • 152
  • 2
  • 3
  • What is the original object and what is the clone? doens't seem to work for me – LobsterMan Mar 03 '13 at 15:36
  • 1
    This is a bad and unclear code example - additionally, I suspect it is outdated and doesn't work with contemporary browsers. – Hakan Bilgin May 12 '16 at 08:32
  • 1
    Hakan, the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#Syntax) says this is valid, and it worked for me. I submitted an edit to clarify this. – Aljoscha Meyer May 15 '16 at 10:59
  • So each of these lines alone would be enough, or the pair of two lines is required? If you need both lines, what does the first line on its own do? – hippietrail Sep 10 '19 at 14:43
  • 1
    @hippietrail - The [`new` operator](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/new) is used to create a new instance of a constructor so in theory: *1st line=clone structure, 2nd line=copy data*... However **this method didn't actually work** for me, but the [other answer](https://stackoverflow.com/a/48078441/8112776) did what I needed, perhaps because the other answer includes the [`ImageData()` function](https://developer.mozilla.org/docs/Web/API/ImageData/ImageData) to actually create the [`ImageData` object](https://developer.mozilla.org/docs/Web/API/ImageData). – ashleedawg Sep 10 '21 at 22:33
  • @hippietrail - ...on second thought, after wasting a bunch of time with these methods, I realized I can "clone" canvas image data by ***simply by assigning it to a new variable***. See [my answer](https://stackoverflow.com/a/69139235/8112776) with **demo** below. – ashleedawg Sep 11 '21 at 00:56
-3

Most times it should be sufficient to simply assign the imageData to a new variable, just like:

myImgData=ctx.getImageData(0,0,c.width,c.height); //get image data somewhere
imgDataCopy = myImgData;   // clone myImgData

...now imgDataCopy contains a separate copy of myImgData. ‍♂️


Demo

The snippet below creates 4 "frames" in an array of ImageData's and then loop through them.

const c = document.getElementById('canvas'),
      ctx = c.getContext("2d");
var wh=70, iDatas=[], i=0,
    lines=[[10,10,wh-10,wh-10], [wh/2,5,wh/2,wh-5],  // ⤡,↕
           [wh-10,10,10,wh-10], [5,wh/2,wh-5,wh/2]]; // ⤢,↔
c.width=wh;
c.height=wh;

ctx.strokeStyle='blue'; //setup to draw
ctx.lineWidth=9;
ctx.lineWidth='round';

for(var [x1,y1,x2,y2] of lines){ 
  ctx.beginPath();
  ctx.moveTo(x1,y1); //draw something
  ctx.lineTo(x2,y2);
  ctx.stroke();
  var d=ctx.getImageData(0,0,c.width,c.height); //get imgdata
  iDatas.push( d ); //save imgdata to array
  ctx.clearRect(0, 0, c.width, c.height); //clear canvas
}

ctx.strokeStyle='green'; //❌has no effect: 
  //  ↑ shows that color data comes from the source (can't be changed)
ctx.lineWidth='round'; //❌has no effect: 
  //  ↑ shows that non-color styling does NOT come from source (CAN'T be changed)

//now you can refer to the image data as iData[i] where i= 0 to 3
drawFrame();
function drawFrame(){
  ctx.putImageData( iDatas[i],0,0); //draw imgData from array
  i=(i==3?0:i+1); //set next iteration #
  setTimeout(function(){ drawFrame() }, 100); //schedule next frame
}
canvas{ border:2px dotted salmon; }
<canvas id='canvas'></canvas>
ashleedawg
  • 20,365
  • 9
  • 72
  • 105