ImageData transformation speed up

I am trying to colorize a large image using a d3 interpolated color scheme and running into 2 issues:

  • unexpected factor of 2 rescaling
  • slow performance

Both issues are demonstrated in Colorize / David Kirkby / Observable where the image data transform is working correctly (except for the 2x rescaling), but too slow for my application which involves 6000x6000 images. Is there a different approach that would be faster? I do not need (or want) to display the large source image at all, so OffscreenCanvas looked promising but still experimental so not widely supported.

I’ve sent you two suggestions:

  1. set the third argument to DOM.canvas to 1 so we don’t quadruple the number of pixels on a retina screen
  2. create a look-up table (LUT) of interpolated colors, to make the transform faster (6000x6000 will still be a bit slow)

Excellent, thanks @Fil! Those two suggestions bring the processing time down to a few secs for a 6000x6000 image, making this quite usable.


In case anyone lands here with a similar issue, I updated my simple example with @Fil’s suggestions and also replaced the ImageBitmap (which I discovered is not available on Safari) with an HTMLCanvasElement.

1 Like

You can speed up things further by using a Uint32Array data view for your colors.

First, we create an array of all colors (your lookup table) as 32-bit values:

function getPalette(num, colorFn) {
  const c = DOM.context2d(num, 1, 1);
  for(let i = 0; i < num; i++) c.fillStyle = colorFn(i), c.fillRect(i, 0, 1, 1);
  return new Uint32Array(c.getImageData(0, 0, num, 1).data.buffer);


  // [...]
  // generate the colors
  const LUT = getPalette(256, i => d3.color(interpolator(i / 255)));
  // [...]
  // create a 32-bit data view of your Uint8ClampedArray
  const uint32 = new Uint32Array(;
  // lookup and assign colors for all values
  for(let i = 0; i < uint32.length; i++) uint32[i] = LUT[[i*4]];
  // [...]
1 Like

Even better, thanks @mootari!

1 Like