How to know when browser finish to process an image after loading it?

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.

Leave a Comment