<!doctype html>
<canvas></canvas>
<script>
async function render(ctx, imgBase64, width, height) {
  ctx.clearRect(0, 0, width, height);
  const img = new Image();
  const loaded = new Promise(resolve => img.addEventListener("load" , resolve, false));
  img.src = `data:image/png;base64,${imgBase64}`;
  await loaded;
  ctx.drawImage(img, 0, 0);
  return ctx.getImageData(0, 0, width, height);
}

function compareImgData(img1, img2) {
  if (img1.width !== img2.width) {
    throw new Error(`Image widths don't match; got ${img1.width} and ${img2.width}`)
  }
  if (img1.height !== img2.height) {
    throw new Error(`Image heights don't match; got ${img1.height} and ${img2.height}`)
  }

  const result = {totalPixels: 0, maxDifference: 0};

  const img1Data = img1.data;
  const img2Data = img2.data;

  let idx = 0;
  while (idx < img1Data.length) {
    let maxDifference = 0;
    for (let channel = 0; channel < 4; channel++) {
      const difference = Math.abs(img1Data[idx + channel] - img2Data[idx + channel]);
      if (difference > maxDifference) {
        maxDifference = difference
      }
    }
    if (maxDifference > 0) {
      result.totalPixels += 1;
      if (maxDifference > result.maxDifference) {
        result.maxDifference = maxDifference;
      }
    }
    idx += 4;
  }
  return result;
}

/**
 * Compare two images for equality.
 *
 * @param {string} img1 - base64-encoded string of image 1
 * @param {string} img2 - base64-encoded string of image 2
 * @param {number} width - Image width in pixels
 * @param {number} height - Image height in pixels
 * @returns {Promise<Object>} - A promise that resolves to an object containing `totalPixels`; the
 *                              number of pixels different between the images, and `maxDifference`
 *                              the maximum difference in any color channel.
 */
async function compare(img1, img2, width, height) {
  const canvas = document.getElementsByTagName("canvas")[0];
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext("2d");

  let img1Data = await render(ctx, img1, width, height);
  let img2Data = await render(ctx, img2, width, height);
  return compareImgData(img1Data, img2Data, width, height);
}
</script>
