Canvas Pixel Manipulation (v168)

Revision 168 of this benchmark created by Chadnaut on


Description

Tests different methods of manipulating pixels using the canvas. *Removed non-performant fillRect & 1px canvas, renamed snippets.

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,
    
      r = [],
      g = [],
      b = [],
      a = [],
      b32 = [],
      v32 = [];
    
    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);
        b32.push((alpha << 24) | (blue << 16) | (green << 8) | red);
        v32.push((red << 24) | (green << 16) | (blue << 8) | alpha);
      }
    }
    
    var mr = r[0],
      mg = g[0],
      mb = b[0],
      ma = a[0],
      mb32 = b32[0],
      mv32 = v32[0];

Test runner

Ready to run.

Testing in
TestOps/sec
putImageData Ref
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    data[p+0] = r[i];
    data[p+1] = g[i];
    data[p+2] = b[i];
    data[p+3] = 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++, p+=4) {
    imageData.data[p+0] = r[i];
    imageData.data[p+1] = g[i];
    imageData.data[p+2] = b[i];
    imageData.data[p+3] = 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++, p+=4) {
    tempData[p+0] = r[i];
    tempData[p+1] = g[i];
    tempData[p+2] = b[i];
    tempData[p+3] = a[i];
  }
}
ctx.putImageData(temp, 0, 0);
ready
32-bit Set
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    data32[i] = b32[i];
  }
}
imageData.data.set(buf8);
ctx.putImageData(imageData, 0, 0);
ready
32-bit Direct
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    pixelsI32[i] = b32[i];
  }
}
ctx.putImageData(imageData, 0, 0);
ready
32-bit Uint
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    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
putImageData Ref Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    data[p+0] = mr;
    data[p+1] = mg;
    data[p+2] = mb;
    data[p+3] = ma;
  }
}
ctx.putImageData(imageData, 0, 0);
ready
putImageData Direct Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    imageData.data[p+0] = mr;
    imageData.data[p+1] = mg;
    imageData.data[p+2] = mb;
    imageData.data[p+3] = ma;
  }
}
ctx.putImageData(imageData, 0, 0);
ready
putImageData Temp Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    tempData[p+0] = mr;
    tempData[p+1] = mg;
    tempData[p+2] = mb;
    tempData[p+3] = ma;
  }
}
ctx.putImageData(temp, 0, 0);
ready
32-bit Set Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    data32[i] = mb32;
  }
}
imageData.data.set(buf8);
ctx.putImageData(imageData, 0, 0);
ready
32-bit Direct Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    pixelsI32[i] = mb32;
  }
}
ctx.putImageData(imageData, 0, 0);
ready
32-bit Uint Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    pixelsU32[i] = mb32;
  }
}
ctx.putImageData(imageData, 0, 0);
ready
32-bit DataView Mono
for (var i=0, p=0, y=0; y < canvasHeight; y++) {
  for (var x=0; x < canvasWidth; x++, i++, p+=4) {
    view.setUint32(p, mv32);
  }
}
ctx.putImageData(imageData, 0, 0);
ready

Revisions

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