Canvas Pixel Manipulation

JavaScript performance comparison

Revision 167 of this test case created by Chadnaut

Preparation code

<canvas id="canvas" height="256" width="256"></canvas>
      
<script>
Benchmark.prototype.setup = function() {
  //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);
    }
  }

};
</script>

Preparation code output

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

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/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);
pending…
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);
pending…
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);
pending…
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);
  }
}
pending…
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);
pending…
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);
pending…
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);
pending…
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);
pending…
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);
  }
}
pending…
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);
  }
}
pending…
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);
  }
}
pending…

Compare results of other browsers

Revisions

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

0 Comments