21

I want to create a new ImageData object in code. If I have a Uint8ClampedArray out of which I want to make an image object, what is the best way to do it?

I guess I could make a new canvas element, extract its ImageData and overwrite its data attribute, but that seems like a wrong approach.

It would be great if I could use the ImageData constructor directly, but I can't figure out how to.

Likhit
  • 799
  • 2
  • 6
  • 18
  • 2
    This seems to have inspired a fix to the spec to make it easier https://www.w3.org/Bugs/Public/show_bug.cgi?id=24301 – Domenic Jan 15 '14 at 20:45
  • 2
    @Domenic ha ha, thanks for the link. I'm actually feeling rather proud now, although I know it isn't a big deal. But hey, a student's question leading to a revision of the spec isn't a small deal either. – Likhit Feb 22 '14 at 06:12

4 Answers4

39

This is interesting problem... You can't just create ImageData object:

var test = new ImageData(); // TypeError: Illegal constructor

I have also tried:

var imageData= context.createImageData(width, height);
imageData.data = mydata; // TypeError: Cannot assign to read only property 'data' of #<ImageData> 

but as described in MDN data property is readonly.

So I think the only way is to create object and set data property with iteration:

var canvas = document.createElement('canvas');
var imageData = canvas.getContext('2d').createImageData(width, height);
for(var i = 0; i < myData.length; i++){
    imageData.data[i] = myData[i];
}

Update: I have discovered the set method in data property of ImageData, so solution is very simple:

var canvas = document.createElement('canvas');
var imageData = canvas.getContext('2d').createImageData(width, height);
imageData.data.set(myData);
hamczu
  • 1,774
  • 12
  • 14
  • 1
    where did you find `set`? It's not mentioned in MDN – twinlakes Dec 24 '13 at 07:19
  • @programminginallston, ImageData's data is a Uint8ClampedArray :) – Danguafer Jan 10 '14 at 00:34
  • 1
    @twinlakes for futher reference on ImageData Uint8clampedarrays check [this](http://www.javascripture.com/Uint8ClampedArray). – Paulo Bueno Jun 23 '14 at 22:57
  • This answer is the most upvoted but at the same time is outdated. Please check the other answers, in particular suggesting `ImageData` constructor - as for me that is better and way more concise. – 1valdis Feb 07 '20 at 09:25
12

All modern browsers including Chrome, Edge, Firefox and Safari support the ImageData constructor. You can find its definition at MDN.

You can use it like this:

let imgData1 = new ImageData(data, width, height);
let imgData2 = new ImageData(width, height);

For very old browsers you can create this constructor yourself:

function ImageData() {
    var i = 0;
    if(arguments[0] instanceof Uint8ClampedArray) {
        var data = arguments[i++];
    }
    var width = arguments[i++];
    var height = arguments[i];      
    
    var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext('2d');
    var imageData = ctx.createImageData(width, height);
    if(data) imageData.data.set(data);
    return imageData;
}
joe
  • 3,752
  • 1
  • 32
  • 41
Luka
  • 2,779
  • 3
  • 17
  • 32
3

The ImageData constructor is finally becoming available in Chrome and Firefox (see the compatibility table on mdn). There are two forms:

var imageData = new ImageData(width, height);

and if you want to build an instance with a UInt8ClampedArray object data:

var imageData = new ImageData(data, width, height); // height is optional

For compatibility reasons, it's best to use createImageData via a canvas 2D context though, as demonstrated in other answers.

qubyte
  • 17,558
  • 3
  • 30
  • 32
0

There is the createImageData() method. But for this you need the context of an existing canvas.

var myImageData = context.createImageData(cssWidth, cssHeight);

See here for more information.

Mouagip
  • 5,139
  • 3
  • 37
  • 52