Canvas Pixel Manipulation (v167)

Revision 167 of this benchmark created by Chadnaut on


Description

Tests different methods of manipulating pixels using the canvas.

Preparation HTML

<canvas id="canvas" height="256" width="256"></canvas>

Setup

//precompute everything to only test raw pixel pushing performance
    var canvas = document.getElementById('canvas'),
      canvasWidth = canvas.width,
      canvasHeight = canvas.height,
      ctx = canvas.getContext('2d'),
    
      imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight),
      data = imageData.data,
    
      buf = new ArrayBuffer(data.length),
      buf8 = new Uint8ClampedArray(buf),
      data32 = new Uint32Array(buf),
    
      pixelsI32 = new Int32Array(data.buffer),
      pixelsU32 = new Uint32Array(data.buffer),
      view = new DataView(data.buffer),
    
      temp = ctx.createImageData(canvasWidth, canvasHeight),
      tempData = temp.data,
      px = ctx.createImageData(1, 1),
      pxData = px.data,
    
      r = [],
      g = [],
      b = [],
      a = [],
      hex = [],
      rgb = [],
      rgba = [],
      b32 = [],
      v32 = [];
    
    ctx.globalAlpha = 1;
    
    for (var y = 0; y < canvasHeight; y++) {
      for (var x = 0; x < canvasWidth; x++) {
        var red = x * y & 0xff,
          green = x & 0xff,
          blue = y & 0xff,
          alpha = 255;
    
        r.push(red);
        g.push(green);
        b.push(blue);
        a.push(alpha);
        rgb.push('rgb(' + red + ',' + green + ',' + blue + ')');
        rgba.push('rgba(' + red + ',' + green + ',' + blue + ',' + (alpha / 255) + ')');
        hex.push("#" + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1));
        b32.push((alpha << 24) | (blue << 16) | (green << 8) | red);
        v32.push((red << 24) | (green << 16) | (blue << 8) | alpha);
      }
    }

Test runner

Ready to run.

Testing in
TestOps/sec
putImageData
for (var i = 0, p = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    data[p++] = r[i];
    data[p++] = g[i];
    data[p++] = b[i];
    data[p++] = a[i];
  }
}
ctx.putImageData(imageData, 0, 0);
ready
putImageData Direct
for (var i = 0, p = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    imageData.data[p++] = r[i];
    imageData.data[p++] = g[i];
    imageData.data[p++] = b[i];
    imageData.data[p++] = a[i];
  }
}
ctx.putImageData(imageData, 0, 0);
ready
putImageData Temp
for (var i = 0, p = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    tempData[p++] = r[i];
    tempData[p++] = g[i];
    tempData[p++] = b[i];
    tempData[p++] = a[i];
  }
}
ctx.putImageData(temp, 0, 0);
ready
putImageData 1PX
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    pxData[0] = r[i];
    pxData[1] = g[i];
    pxData[2] = b[i];
    pxData[3] = a[i];
    ctx.putImageData(px, x, y);
  }
}
ready
32-bit
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    data32[i] = b32[i];
  }
}
imageData.data.set(buf8);
ctx.putImageData(imageData, 0, 0);
ready
32-bit Direct
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    pixelsI32[i] = b32[i];
  }
}
ctx.putImageData(imageData, 0, 0);
ready
32-bit Uint
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    pixelsU32[i] = b32[i];
  }
}
ctx.putImageData(imageData, 0, 0);
ready
32-bit DataView
for (var i = 0, p = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++, p += 4) {
    view.setUint32(p, v32[i]);
  }
}
ctx.putImageData(imageData, 0, 0);
ready
fillRect RGBA
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    ctx.fillStyle = rgba[i];
    ctx.fillRect(x, y, 1, 1);
  }
}
ready
fillRect RGB
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    ctx.fillStyle = rgb[i];
    ctx.fillRect(x, y, 1, 1);
  }
}
ready
fillRect HEX
for (var i = 0, y = 0; y < canvasHeight; y++) {
  for (var x = 0; x < canvasWidth; x++, i++) {
    ctx.fillStyle = hex[i];
    ctx.fillRect(x, y, 1, 1);
  }
}
ready

Revisions

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