Search code examples
javascriptperformancergbweb-workertyped-arrays

canvas RGBA to RGB conversion


I have RGBA image from canvas and I use typedArray to remove alpha channel.

// data - arr from canvas. 

// [1,2,3,255, 1,2,3,255, 1,2,3,255,]
//  R G B  A   R G B  A   R G B  A

  const delta = 4;
  const length = data.length;
  const newLength = length - length / delta;

  const rgbArr = new Uint8Array(newLength);

  let j = 0;

  for (i = 0; i < data.length; i = i + delta) {
    rgbArr[j] = data[i]; // R
    rgbArr[j + 1] = data[i + 1]; // G
    rgbArr[j + 2] = data[i + 2]; // B
    j = j + 3;
  }
 
  // rgbArr [1,2,3, 1,2,3, 1,2,3]

I copy every 3 bytes to new Uint8Array. Can I do it in more optimized way without byte copying?


Solution

  • Looks like your solution is pretty good. At least none of the alternatives I came up with so far comes anywhere close in performance. Run the snippet to see for yourself.

    Updated with Justin's suggestion using .filter -- elegant but not faster.

    const data = new Uint8Array(1e8);
    
    const delta = 4;
    const length = data.length;
    const newLength = length - length / delta;
    
    const rgbArr = new Uint8Array(newLength);
    
    let j = 0;
    
    console.time('first');
    for (i = 0; i < data.length; i = i + delta) {
      rgbArr[j] = data[i]; // R
      rgbArr[j + 1] = data[i + 1]; // G
      rgbArr[j + 2] = data[i + 2]; // B
      j = j + 3;
    }
    console.timeEnd('first');
    
    j = 0;
    console.time('set');
    const rgbArr2 = new Uint8Array(newLength);
    for (i = 0; i < data.length; i = i + delta) {
      rgbArr2.set(data.slice(i, i+2), j);
      j = j + 3;
    }
    console.timeEnd('set');
    
    console.time('filter');
    data.filter((el,i) => {
      return i % 4 !== 4 - 1
    })
    console.timeEnd('filter');
    
    j = 0;
    console.time('copyWithin');
    for (i = 0; i < data.length; i = i + delta) {
      data.copyWithin(j, i, i+2);
      j = j + 3;
    }
    console.timeEnd('copyWithin');

    Results:

    first: 102.900ms
    set: 1185.700ms
    filter: 2779.800ms
    copyWithin: 415.100ms