putImageData vs JS PNG vs JS BMP

JavaScript performance comparison

Revision 2 of this test case created

Preparation code

<canvas>
</canvas>
<script src="http://www.xarg.org/download/pnglib.js">
</script>
<script>
  //From https://github.com/maz/bmp.js
  this.BMP = (function() {
    var header = new Uint8Array([0x42, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);

    function BMP(w, h) {
      var pixel_sze = 4 * w * h;
      var sze = header.length + pixel_sze;
      this.data = new Uint8Array(sze);
      this.data.set(header);
      this.width = w;
      this.height = h;
      var view = new DataView(this.data.buffer);
      view.setInt32(0x02, sze, true);
      view.setInt32(0x12, w, true);
      view.setInt32(0x16, -h, true);
      view.setInt32(0x22, pixel_sze, true);
      this.pixels = this.data.subarray(header.length);
    }
    var BASE64_CHUNK_SIZE = 100;
    BMP.prototype.toBase64 = function() {
      var str = "";
      for (var i = 0; i < this.data.length; i += BASE64_CHUNK_SIZE) {
        str += String.fromCharCode.apply(String, this.data.subarray(i, i + BASE64_CHUNK_SIZE));
      }
      return btoa(str);
    };
    BMP.prototype.toDataURL = function() {
      return "data:image/bmp;base64," + this.toBase64();
    };
    return BMP;
  })();
</script>
<script>
  var img = document.getElementById('img');
  var width = 400,
      height = 300;
  var canvas = document.getElementsByTagName('canvas')[0];
  var context = canvas.getContext('2d');
  canvas.width = width;
  canvas.height = height;
  context.fillStyle = '#ffcc00';

  var rand = function(min, max) {
      var r;
      do {
        r = Math.random();
      } while (r === 1.0);
      return min + parseInt(r * (max - min + 1), 10);
      };

  var data = [];
  for (var i = 0; i < width * height; i++) {
    data[i] = {
      r: rand(0, 255),
      g: rand(0, 255),
      b: rand(0, 255),
      a: rand(0, 255)
    };
  }
</script>
<img id="img" width="400" height="300" />

Preparation code output

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
putImageData
var imgData = context.getImageData(0, 0, width, height),
    pixels = imgData.data;

var k, p;
for (var i = 0, il = data.length; i < il; i++) {
  k = i * 4;
  p = data[i];
  pixels[k] = p.r;
  pixels[k + 1] = p.g;
  pixels[k + 2] = p.b;
  pixels[k + 3] = p.a;
}

context.putImageData(imgData, 0, 0);
var res = canvas.toDataURL();
pending…
JS PNG
var png = new PNGlib(width, height);
var k, p;
for (var i = 0, il = data.length; i < il; i++) {
  k = i * 2;
  p = data[i];
  png.buffer[png.index(k, k + 1)] = png.color(p.r, p.g, p.b, p.a);
}

//var res = 'data:image/png;base64,' + png.getBase64();
pending…
JS BMP
//From http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
// Class containing image data

function image(w, h) {
  this.header = '';
  this.data = Array();
  this.width = w;
  this.height = h;
}

// Convert a value to a little endian hexadecimal value

function getLittleEndianHex(value) {
  var result = [];

  for (var bytes = 4; bytes > 0; bytes--) {
    result.push(String.fromCharCode(value & 255));
    value >>= 8;
  }

  return result.join('');
}

// Set the required bitmap header

function setImageHeader(img) {
  var numFileBytes = getLittleEndianHex(img.width * img.height);
  var w = getLittleEndianHex(img.width);
  var h = getLittleEndianHex(img.height);

  img.header = 'BM' + // Signature
  numFileBytes + // size of the file (bytes)*
  '\x00\x00' + // reserved
  '\x00\x00' + // reserved
  '\x36\x00\x00\x00' + // offset of where BMP data lives (54 bytes)
  '\x28\x00\x00\x00' + // number of remaining bytes in header from here (40 bytes)
  w + // the width of the bitmap in pixels*
  h + // the height of the bitmap in pixels*
  '\x01\x00' + // the number of color planes (1)
  '\x20\x00' + // 32 bits / pixel
  '\x00\x00\x00\x00' + // No compression (0)
  '\x00\x00\x00\x00' + // size of the BMP data (bytes)*
  '\x13\x0B\x00\x00' + // 2835 pixels/meter - horizontal resolution
  '\x13\x0B\x00\x00' + // 2835 pixels/meter - the vertical resolution
  '\x00\x00\x00\x00' + // Number of colors in the palette (keep 0 for 32-bit)
  '\x00\x00\x00\x00'; // 0 important colors (means all colors are important)
}

// Flip image vertically

function flipImage(img) {
  var newImgData = new Array();

  for (var x = 0; x < img.width; x++) {
    for (var y = 0; y < img.height; y++) {
      var ny = img.height - 1 - y;
      newImgData[(ny * img.width) + x] = img.data[(y * img.width) + x];
    }
  }

  img.data = newImgData;
}

// Main draw function

function drawImage() {
  var img = new image(400, 300);

  setImageHeader(img);

  for (var i = 0, il = data.length; i < il; i++) {
    p = data[i];
    img.data[i] = String.fromCharCode(p.r, p.g, p.b, p.a);
  }

  // Flip image vertically     
  flipImage(img);

  return 'data:image/bmp;base64,' + btoa(img.header + img.data.join(""));
}

img.src = drawImage();
pending…
BMP.js
var bmp = new BMP(400, 300);
for (var i = 0, il = data.length; i < il; i++) {
  var k = i * 4;
  p = data[i];
  bmp.pixels[k] = p.r;
  bmp.pixels[k + 1] = p.g;
  bmp.pixels[k + 2] = p.b;
  bmp.pixels[k + 3] = p.a;
}
img.src = bmp.toDataURL();
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. Here’s a list of current revisions for this page:

0 comments

Add a comment