canvas image and data uri

Playing with canvas and images these days, I suggest to look further on what happens with toDataUrl() Canvas javascript API method and why it may be useful to you too.

First, I let you read carefully :) what is a data URI (Uniform Resource Identifier).

It allow content creators to embed small files inline in documents.

My interpretation is you can "serialize" external data and make it available as an inline browser resource.

Data URI format specification

data:[<mediatype>][;base64],<data>

M: mandatory O: optional

(M) MIME type string 'image/png', 'application/zip'... details

(M) some urlchar or sequence of characters details

;base64 (O) encoded string

Extract from specification:

The <mediatype> is an Internet media type specification (with
optional parameters.) The appearance of ";base64" means that the data
is encoded as base64. Without ";base64", the data (as a sequence of
octets) is represented using ASCII encoding for octets inside the
range of safe URL characters and using the standard %xx hex encoding
of URLs for octets outside that range.  If <mediatype> is omitted, it
defaults to text/plain;charset=US-ASCII.  As a shorthand,
"text/plain" can be omitted but the charset parameter supplied.

details

Data URI image sample

Most of the time, we may use data URI for a representation of images content.

You can inspect the DOM and look on this image 'src' attribute

here.

or look at this link

Here is how this data URI looks like:

data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw AAAC8IyPqcvt3wCcD
kiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz ByTB10QgxOR0TqBQejhRNzOfkVJ+5
YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGd
kF8kjdfnycQZXZeYGejmJl ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOz
rcd3iq9uis F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH h
hx4dbgYKAAA7

Note that the tag can use it as content for its 'src' attribute.

<img src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP.." />

Canvas API

I am sure you have already played with Canvas API with your favourite browser

Displaying an image on canvas is trivial and we will dive into a small example with an data URI for fun.

Data URI to canvas

Steps consist simply in creating a Canvas context and displaying an Image object on it.

Image source attribute is not an URL but data URI content in this case and it works !

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var img = new Image();
img.src = 'data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAPywAAA...';

img.onload = function() {
  ctx.drawImage(img, 0, 0);
}

Full example here

Canvas to data URI

We will use an existing image (jpeg, png...) and a canvas to compute a data URI, this canvas will not be displayed but used like a kind of clever buffer.

Note some limitations depending on image mime types well.

Canvas API has a very useful toDataURL(type, encoderOptions) method that being call on canvas context will return a nice dataURI. The default type is image/png.

Let's create an Image first

var img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://fiddle.jshell.net/favicon.png';

Then when image is loaded do the stuff

img.onload = function() {
  // use a canvas to get data URI for image
  var workerCanvas = document.createElement('canvas'),
  workerCtx = workerCanvas.getContext('2d');

  // init
  workerCanvas.width = this.width;
  workerCanvas.height = this.height;

  // fill canvas with image  
  workerCtx.drawImage(this, 0, 0);

  // get data URI for this image
  // call magical function
  var imgDataURI = workerCanvas.toDataURL();
  console.log(imgDataURI);

  // job done

You can now use this data URI and assign it to img tag or display it on another canvas, store it...

  var targetImg = document.getElementById("targetImg");
  var targetCanvas = document.getElementById("targetCanvas");
  var targetCanvasCtx = targetCanvas.getContext('2d');

  // assign it to target image tag  
  targetImg.src = imgDataURI;

  // assign it to target canvas tag  
  targetCanvasCtx.width = this.width;
  targetCanvasCtx.height = this.height;

  var tmpImg = new Image();
  tmpImg.src = imgDataURI;

  targetCanvasCtx.drawImage(tmpImg, 0, 0);

};

See it in action and play, inspect html DOM here

Warning cors is never far

Some of you may have that kind of nice error when using toDataURL() canvas method:

Uncaught SecurityError: Failed to execute 'toDataURL' on 
'HTMLCanvasElement': Tainted canvases may not be exported.

Triggered when you try to make a Cross-Origin Resource Sharing CORS

Previous examples were fine if you are on same domain, otherwise read next to see an alternative.

Instead of calling it from an existing Image object on your DOM, we will use an XMLHttpRequest to get Image content as Blob.

Compatibility check

It works fine with Chrome extension but in other cases...not easy.

function FetchImageAsBlob(url, cb) {  
  var req = createCORSRequest('GET', url);
  req.onload = function() {
    var img = new Image();
    img.onload = function() {
      URL.revokeObjectURL(this.src);
      cb(null, img);
    };
    img.src = URL.createObjectURL(req.response);
  };
  req.onerror = function(e) {
    cb(e);
  };  
  req.responseType = 'blob';
  req.send();
}

Code here, you can look at console and see error.

Small gist

Conclusion

Data URI is a nice standard but with limitations for image like : size, types, browser compatibility...

You may also try using it for other kind a resource that image (xml, video, audio, zip...)

Just for fun


Tags: Javascript Canvas