createImageBitmap alternative on Safari
I'd like to generate images in a bit of asm.js code running on a web worker. And I'd like to regularly composite the latest state of that computation onto a user-visible 2d canvas, together with some other content. Currently I have code which
- constructs an
ImageData
object using its constructor, based on a portion of the array buffer used by the asm.js code, - calls
createImageBitmap
to turn theImageData
into anImageBitmap
, - transfers that image bitmap from the worker to the GUI thread and
- uses that
ImageBitmap
as an argument toCanvasRenderingContext2D.drawImage
.
Things work nicely in recent Chrome and Firefox, but Safari 9.1.3 apparently has no createImageBitmap
function. How would I do something like the above in a way that works on Safari?
Is there some low-cost encoding of images, short of creating a data:image/png…
for it? Is there some other way to turn a byte array into something you can feed to drawImage
?
By the way: http://caniuse.com/ currently doesn't list this feature. There is a feature request which you can 👍 if you would like to see this feature monitored there.
If you prefer to see code for my current approach, here is the relevant portion of my worker:
var buffer = new ArrayBuffer(bufferSize);
var asm = Module.asm(self, {}, buffer);
var imgBytes = new Uint8ClampedArray(buffer, offset);
var imgData = new ImageData(imgBytes, width, height);
createImageBitmap(imgData).then(function(bmp) { // Not available on Safari!
postMessage(bmp, [bmp]);
});
and here the corresponding GUI thread code:
var worker = new Worker(‹url of worker›);
worker.onmessage = function(msg) {
var img = msg.data;
context2d.drawImage(img, 0, 0, width, height);
};
The actual unabridged code is in this GitHub pull request, but there is a lot of other stuff which is irrelevant for the question at hand.
Is there some other way to turn a byte array into something you can feed to
drawImage
?
You can post the ArrayBuffer
of Uint8ClampedArray
object to main thread; at main thread substitute using .putImageData()
for .drawImage()
. As indicated by @Kaiido, it is not necessary to create an ImageData
object at Worker
var imgBytes = new Uint8ClampedArray(buffer, offset);
postMessage(imgBytes.buffer, [imgBytes.buffer]);
at main thread
worker.onmessage = function(e) {
console.log(e.data); // `ArrayBuffer`
ctx.putImageData(new ImageData(new Uint8ClampedArray(e.data), width, height), 0, 0);
}
http://plnkr.co/edit/N0v1YQHQX2rdFfHcOKeR?p=preview