loading images: blobs vs dataurls (v3)

Revision 3 of this benchmark created on


Preparation HTML

<canvas id="cvs" width="300" height="300">
</canvas>
<script>
/* canvas-toBlob.js
 * A canvas.toBlob() implementation.
 * 2013-12-27
 * 
 * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
 * License: X11/MIT
 *   See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md
 */

/*global self */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
  plusplus: true */

/*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */

(function(view) {
"use strict";
var
    Uint8Array = view.Uint8Array
  , HTMLCanvasElement = view.HTMLCanvasElement
  , canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype
  , is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i
  , to_data_url = "toDataURL"
  , base64_ranks
  , decode_base64 = function(base64) {
    var
        len = base64.length
      , buffer = new Uint8Array(len / 4 * 3 | 0)
      , i = 0
      , outptr = 0
      , last = [0, 0]
      , state = 0
      , save = 0
      , rank
      , code
      , undef
    ;
    while (len--) {
      code = base64.charCodeAt(i++);
      rank = base64_ranks[code-43];
      if (rank !== 255 && rank !== undef) {
        last[1] = last[0];
        last[0] = code;
        save = (save << 6) | rank;
        state++;
        if (state === 4) {
          buffer[outptr++] = save >>> 16;
          if (last[1] !== 61 /* padding character */) {
            buffer[outptr++] = save >>> 8;
          }
          if (last[0] !== 61 /* padding character */) {
            buffer[outptr++] = save;
          }
          state = 0;
        }
      }
    }
    // 2/3 chance there's going to be some null bytes at the end, but that
    // doesn't really matter with most image formats.
    // If it somehow matters for you, truncate the buffer up outptr.
    return buffer;
  }
;
if (Uint8Array) {
  base64_ranks = new Uint8Array([
      62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1
    , -1, -1,  0, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9
    , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
    , -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
    , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
  ]);
}
if (HTMLCanvasElement && !canvas_proto.toBlob) {
  canvas_proto.toBlob = function(callback, type /*, ...args*/) {
      if (!type) {
      type = "image/jpeg";
    } if (this.mozGetAsFile) {
      callback(this.mozGetAsFile("canvas", type));
      return;
    } if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) {
      callback(this.msToBlob());
      return;
    }

    var
        args = Array.prototype.slice.call(arguments, 1)
      , dataURI = this[to_data_url].apply(this, args)
      , header_end = dataURI.indexOf(",")
      , data = dataURI.substring(header_end + 1)
      , is_base64 = is_base64_regex.test(dataURI.substring(0, header_end))
      , blob
    ;
    if (Blob.fake) {
      // no reason to decode a data: URI that's just going to become a data URI again
      blob = new Blob
      if (is_base64) {
        blob.encoding = "base64";
      } else {
        blob.encoding = "URI";
      }
      blob.data = data;
      blob.size = data.length;
    } else if (Uint8Array) {
      if (is_base64) {
        blob = new Blob([decode_base64(data)], {type: type});
      } else {
        blob = new Blob([decodeURIComponent(data)], {type: type});
      }
    }
    callback(blob);
  };

  if (canvas_proto.toDataURLHD) {
    canvas_proto.toBlobHD = function() {
      to_data_url = "toDataURLHD";
      var blob = this.toBlob();
      to_data_url = "toDataURL";
      return blob;
    }
  } else {
    canvas_proto.toBlobHD = canvas_proto.toBlob;
  }
}
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));

</script>

Setup

cvs = document.getElementById('cvs')
    ctx = cvs.getContext("2d");
    cpa = ctx.createImageData(cvs.width, cvs.height);
    for (var i=0; i<cpa.data.length; i+=4){
      cpa.data[i+0]=Math.round(Math.random()*255);
      cpa.data[i+1]=Math.round(Math.random()*255);
      cpa.data[i+2]=Math.round(Math.random()*255);
      cpa.data[i+3]=255;
    }
    ctx.putImageData(cpa,0,0);
    
    URL = window.URL || window.webkitURL;

Test runner

Ready to run.

Testing in
TestOps/sec
canvas to data url
// async test
var img = new Image();
img.onload = function() {
  deferred.resolve();
}
img.src = cvs.toDataURL();
ready
canvas to blob to object url
// async test
var img = new Image();
var url;
img.onload = function() {
  URL.revokeObjectURL(url);
  deferred.resolve();
}
cvs.toBlob(function(blob) {
  url = URL.createObjectURL(blob);
  img.src = url;
})
 
ready
canvas to blob to file reader to data url
// async test
var img = new Image();
var fileReader = new FileReader();
img.onload = function() {
  deferred.resolve();
}
cvs.toBlob(function(blob) {
  fileReader.readAsDataURL(blob);
})

fileReader.onload = function() {
  img.src = this.result;
};
ready

Revisions

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