HTML5 load a png buffer into a canvas (for streami

2019-03-21 06:43发布

问题:

Through a websocket, I retrieve a binary buffer of an image in a PNG format (something like that).

I want to load this PNG buffer into a canvas, and then read the different pixels to read the uncompressed data.

I managed to do it but it is stupid:

function onBinaryMessage(/*ArrayBuffer*/ input) {
  input = new Uint8Array(input);

  var str = '';
  for (var i = 0; i < input.byteLength; i++)
    str = str + String.fromCharCode(input[i]);

  var image = document.getElementById("image");
  image.src = 'data:image/png;base64,' + btoa(str);

  var c = document.getElementById("canvas");
  var ctx = c.getContext("2d");
  ctx.drawImage(image, 0, 0);
  var imgData = ctx.getImageData(0, 0, image.width, image.height);
  console.log(imgData);
}

I have to convert my binary into a string to encode64 this string, and than I affect my image src to this newly created encoded64 string... The browser have to re-convert this encoded64 data into the original PNG buffer I got...

Is there any way to directement set the canvas buffer? Or is there any method to better handle streaming?

I think I could use the File API to write the buffer into a temporary file but it would cost a lot to create a file :(

Any suggestion?

回答1:

You can convert your input buffer to a Blob instead, obtain an URL for it and use that to draw onto the canvas instead:

function onBinaryMessage(input) {

    var blob = new Blob([input], {type: 'image/png'});
    var url = URL.createObjectURL(blob);
    var img = new Image;

    img.onload = function() {
        var ctx = document.getElementById("canvas").getContext('2d');
        ctx.drawImage(this, 0, 0);
        URL.revokeObjectURL(url);
    }
    img.src = url;
}

Just note that this will be asynchronous and you would need to provide a callback-mechanism inside the onload handler (in any case you really need to do that in your own example as well). But you won't have to convert to base64 etc. which is a relative costly operation.

Also note that URL.createObjectURL is currently experimental.