The HTMLImageElement interface has a decode()
method, which does allow us to wait until the image is ready to be drawn, just like you want.
var BIGimage;
putBIGimage();
function putBIGimage() {
BIGimage = document.createElement("IMG");
BIGimage.height = 200;
BIGimage.src = "https://upload.wikimedia.org/wikipedia/commons/c/cf/Black_hole_-_Messier_87.jpg?r=" + Math.random();
BIGimage.onload = e => console.log('load event', performance.now());
BIGimage.decode().then(waitBIGimage);
BIGimage.onerror = console.error;
}
function waitBIGimage() {
// uses the synchronous testing method to check it works fine
var start = performance.now();
// only to see if it worked fine
var ctx = document.createElement('canvas').getContext('2d');
ctx.drawImage(BIGimage, 0, 0);
ctx.drawImage(ctx.canvas, 0, 0);
var end = performance.now();
console.log(`it took ${end - start}ms to draw`)
// do your stuff
document.body.appendChild(BIGimage);
}
Another way, is to use the fact that the CanvasContext2D drawImage
method can be synchronous. Some browsers may try to delay the actual painting for the next painting frame, but by drawing the canvas onto itself we can force most of the current UAs to render our image synchronously.
So you can use it as a waiting method in your waitBIGimage
method.
var BIGimage;
putBIGimage();
function putBIGimage() {
BIGimage = document.createElement("IMG");
BIGimage.height = 200;
BIGimage.src = "https://upload.wikimedia.org/wikipedia/commons/c/cf/Black_hole_-_Messier_87.jpg?r=" + Math.random();
BIGimage.onload = waitBIGimage;
BIGimage.onerror = console.error;
}
function waitBIGimage() {
// only for demo
// we've got to also log the time since even the console.log method will be blocked during processing
var start = performance.now();
console.log('waiting', start);
// this is all needed
var ctx = document.createElement('canvas').getContext('2d');
ctx.drawImage(BIGimage, 0, 0);
// on some system the drawing of the image may be delayed to the next painting frame
// we can try force the synchronous rendering by drawing the canvas over itself
ctx.drawImage(ctx.canvas, 0, 0);
// demo only
var end = performance.now();
console.log("Complete.", end);
console.log(`it took ${end - start}ms`)
// do your stuff
document.body.appendChild(BIGimage);
}
On my Firefox it takes about 1 second to process the image, while on my Chrome, it’s a bit faster.
But one big issue with method is that it is synchronous, and thus will block your scripts during all the time the Image is processed.
Yet another way, is to use the createImageBitmap()
method, which should allocate the image bitmap in the GPU, ready to be painted.