createImageBitmap resize vs canvas (v3)

Revision 3 of this benchmark created on


Description

Firefox currently has a bug where resizeWidth/Height is not properly working and results in the image being squished or squashed. https://bugzilla.mozilla.org/show_bug.cgi?id=1733559

Initial setup code is visually inspectable at https://codesandbox.io/s/createimagebitmap-benchmark-setup-jldf3z?file=/src/index.js:0-4065

Preparation HTML

<img id="source" src="https://placekitten.com/1280/720" crossorigin="anonymous">

Setup

// const sourceImage = new Image();
const sourceImage = document.querySelector('#source');
const imageLoaded = new Promise((resolve, reject) => {
  if (sourceImage.complete) resolve(sourceImage);
  sourceImage.onload = () => resolve(sourceImage);
  sourceImage.onerror = reject;
  // resolve(source1);
});

function scaleSource(sw, sh, dw, dh) {
  const hRatio = dw / sw;
  const vRatio = dh / sh;
  const ratio = Math.max(hRatio, vRatio);
  const x = (sw - dw / ratio) / 2;
  const y = (sh - dh / ratio) / 2;
  return { x, y, w: sw - x * 2, h: sh - y * 2, ratio };
}

const profileWidth = 480;
const profileHeight = 360;

// Remember, all the outputs must be an ImageBitmap to be a fair comparison

// case 1: use createImageBitmap to crop and resize, bugged in firefox but working in Chrome
async function case1_createImageBitmap() {
  const resize = scaleSource(
    source.width,
    source.height,
    profileWidth,
    profileHeight
  );

  const bitmap = await window.createImageBitmap(
    source,
    resize.x,
    resize.y,
    resize.w,
    resize.h,
    {
      resizeWidth: profileWidth,
      resizeHeight: profileHeight
    }
  );

  return bitmap;
}

// case 2: use canvas to crop and resize
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d", { alpha: false });
async function case2_canvas() {
  const resize = scaleSource(
    source.width,
    source.height,
    profileWidth,
    profileHeight
  );

  canvas.width = profileWidth;
  canvas.height = profileHeight;

  ctx.drawImage(
    source,
    resize.x,
    resize.y,
    resize.w,
    resize.h,
    0,
    0,
    profileWidth,
    profileHeight
  );

  return await window.createImageBitmap(
    canvas,
    0,
    0,
    profileWidth,
    profileHeight
  );
}

// case 3: no scaling, use createImageBitmap to copy and allow one-off
// transfer to worker (where presumably scaling would occur) without
// requiring new canvas/context creation
async function case3_scaleInWorker() {
  const bitmap = await window.createImageBitmap(source);
  return bitmap;
}

const holder = [];

Test runner

Ready to run.

Testing in
TestOps/sec
Crop and Resize using createImageBitmap, currently bugged in FF 111.0
case1_createImageBitmap()
	.then(bitmap => bitmap.close())
	.then(() => deferred.resolve());
ready
Crop and Resize using Canvas scaling, usually somewhat slow
case2_canvas()
	.then(bitmap => bitmap.close())
	.then(() => deferred.resolve());
ready
No cropping or scaling on main thread, assume ImageBitmap will be transferred to worker (note: not actually transferred in this benchmark)
case3_scaleInWorker() 
	.then(bitmap => bitmap.close())
	.then(() => deferred.resolve());
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.