5

Hi everyone i am trying to make a html5 cavas application with node.js but i am having a problem i am getting imagedata using getImagedata() and sending it to server as a JSON object to the server that will pass that object to all connected clients but i am getting "Argument 1 of CanvasRenderingContext2D.putImageData does not implement interface ImageData." error on all the other clients. Any help will be appreciated following is the code of client that will send image:

var output = function(mousestartposition , currentmouseposition){
  **lastpositionpic = context.getImageData(0,0,canvas.width ,      canvas.height);**
    var data = {
        mousestartposition : mousestartposition ,
        currentmouseposition:currentmouseposition,
        lastpositionpic : lastpositionpic
    }
    socket.emit('senddraw' , data);
 }

The code of client that will receive image is as follows:

 socket.on('receivedraw' , function(data)
 {
     mousestartposition = data.mousestartposition;
     var currentmouseposition = data.currentmouseposition;
     lastpositionpic = data.lastpositionpic;
     **context.putImageData(lastpositionpic,0,0);** // i am getting error on this line
     draw(currentmouseposition);
 });
markE
  • 102,905
  • 11
  • 164
  • 176
Nauman Bashir
  • 189
  • 1
  • 4
  • 10

1 Answers1

2

The problem arises when you try to serialize an ImageData object using JSON. Any object type information will be stripped off, so when you try to parse it on receive the data will be just a plain object.

In addition, since the image data is typed array and not a regular array, the data will be converted to an object where each index is a property. The ImageData also contains methods which cannot be serialized.

What you need to do is to convert your data before sending:

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

var pic = [];
for(var i = 0; i < lastpositionpic.length; i++) pic.push(lastpositionpic[i]);

var data = {
    width: canvas.width,
    height: canvas.height,
    mousestartposition : mousestartposition ,
    currentmouseposition:currentmouseposition,
    lastpositionpic : pic
}
socket.emit('senddraw' , data);

And back when receiving:

socket.on('receivedraw' , function(data)
{
     mousestartposition = data.mousestartposition;
     var currentmouseposition = data.currentmouseposition;
     lastpositionpic = data.lastpositionpic;

     var idata = context.createImageData(data.width, data.height);
     for(var i = 0; i < idata.data.length; i++) idata.data[i] = lastpositionpic[i];

     context.putImageData(idata,0,0);
     draw(currentmouseposition);
 });

Now, there is a performance penalty involved here as you have to convert to and from. As already mentioned, you could also convert the Uint8ClampedArray from the ImageData object directly, but since each index would end up being a property it would be more costly to send, and to put back together when received.

I am not that familiar with socket on Node.js, but if as any other socket you will probably have a way of sending binary data directly (turns out you can).

If that's the case I would recommend creating a typed array the size of Uint16 x 2 + Int16 x 2 (width, height, mouse x, mouse y) plus the size of ImageData bitmap, write in width and height, mouse position in the header of that array and then write the data itself after it.

This would be the most performant way of sending this kind of data.