▴ Back to top

maxnov.com » $.getImageData

A tiny jQuery plugin that, in conjunction with a Google App Engine back-end, allows cross-domain getImageData with the HTML5 Canvas.

About

This project is aimed at developers who don't have the ability, don't want to or don't have time to create a proxy script on their server to get images from different domains or origins. It enables pixel level access to images from different origins. It works by sending a JSONP request with the URL of the image to Google's servers via the Google App Engine1. The server then converts the image into base64 encoded data URL and sends the image back as a JSON object. This means that the image can be locally included on the website and therefore it can be edited by the canvas tag.


Download

Click here to download the current version of $.getImageData (2.5 KB, minified). Or download the uncompressed source code here (3.5 KB).


Installation

Once you have downloaded $.getImageData, you need to do the following; Include jQuery and the $.getImageData source in your HTML document right before the last body tag, like this:

				<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
				<script src="js/jquery.getimagedata.min.js"></script>
			</body>

Usage

Once you have installed the plugin, you are ready to call the $.getImageData function. The function expects one parameter which must be an object consisting of three properties: url, success and error. url is a string containing the URL of the image you are trying to fetch. success and error are callback functions that are called on successful fetching of the image or failure.

			$.getImageData({
				url: "http://farm4.static.flickr.com/3002/2758349058_ab6dc9cfdc_z.jpg?zz=1",
				success: function(image){
					// Do something with the now local version of the image
				},
				error: function(xhr, text_status){
					// Handle your error here
				}
			});

Examples

Getting an image from another domain and then inverting it

View demo

In the example below, the image (London Skyline from Altitude 6 by Annie Mole) is specified as the url property. The success property is a function that receives one argument, which is the requested image. This callback is called once the image has been loaded locally into the DOM. This means that it can now be put on to the canvas and getImageData can be used on it.

			$.getImageData({
				url: "http://farm4.static.flickr.com/3002/2758349058_ab6dc9cfdc_z.jpg?zz=1",
				success: function(image){

					// Set up the canvas
					var can = document.getElementsByTagName('canvas')[0];
					var ctx = can.getContext('2d');

					// Set the canvas width and heigh to the same as the image
					$(can).attr('width', image.width);
					$(can).attr('height', image.height);

					// Draw the image on to the canvas
					ctx.drawImage(image, 0, 0, image.width, image.height);

					// Get the image data
					var image_data = ctx.getImageData(0, 0,  image.width, image.height);
					var image_data_array = image_data.data;

					// Invert every pixel
					for (var i = 0, j = image_data_array.length; i < j; i+=4) {
						image_data_array[i] = 255 - image_data_array[i];
						image_data_array[i+1] = 255 - image_data_array[i+1];
						image_data_array[i+2] = 255 - image_data_array[i+2];
					}

					// Write the image data to the canvas
					ctx.putImageData(image_data, 0, 0);

				},
				error: function(xhr, text_status){
					// Handle your error here
				}
			});


Loading images from flickr and analysing the colour

View demo

This example loads photos from the flickr public feed. It then takes those images and fetches them using $.getImageData so their data can be read using the canvas. The data is then averaged to get the average colour in each images. The images are then added to the page with their average colour displayed next to them. This is an example of the beginning of an interesting mashup that could be achieved by using flickr as a source of images.

			// Get the flickr stream
			$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=colour&tagmode=any&format=json&jsoncallback=?",
			function(data){

				// For each image
				$.each(data.items, function(i,item){
					$.getImageData({
						url: item.media.m, // This is the URL of the flickr image
						success: analyseAndDraw, // Run this function when image has been fetched
						error: function(xhr, text_status){
							// Handle your error here
						}
					});
				});

			});

			// This creates a canvas, draws the image on to it, gets the average colour of the image and then adds
			// the image to the DOM with the average colour as a background colour to its container
			function analyseAndDraw(image) {
				// Create the canvas and context
				var can = document.createElement('canvas');
				var ctx = can.getContext('2d');

				// Set the canvas dimensions
				$(can).attr('width', image.width);
				$(can).attr('height', image.height);

				// Draw the image to the canvas
				ctx.drawImage(image, 0, 0, image.width, image.height);

				// Get the image data
				var image_data = ctx.getImageData(0, 0,  image.width, image.height);
				var image_data_array = image_data.data;
				var image_data_array_length = image_data_array.length;

				// Array to hold the average totals
				var a=[0,0,0];

				// Accumulate the pixel colours
				for (var i = 0; i < image_data_array_length; i += 4){
					a[0]+=image_data_array[i];
					a[1]+=image_data_array[i+1];
					a[2]+=image_data_array[i+2];
				}

				// Divide by number total pixels
				a[0] = Math.round(a[0]/=(image_data_array_length/3)); // R
				a[1] = Math.round(a[1]/=(image_data_array_length/3)); // G
				a[2] = Math.round(a[2]/=(image_data_array_length/3)); // B

				// Create the container, set its background colour and add it to the DOM
				var imageContainer = $('
'); $(".images").append(imageContainer); // Insert the image to the container $(imageContainer).append(image); }

Specification

Technical Specification

The main function that $.getImageData provides is the server-side image fetching. This is done using a Django project hosted on the Google App Engine1. It is a very simple project and could easily be recreated in PHP or any server-side language. The purpose of $.getImageData is to enable people to get images across domains without the need for any server-side code.


$.getImageData consists of one function that uses the jQuery JSONP Core Plugin (written by Julian Aubourg) which is packaged with this plugin. The reason for using this JSONP plugin is so that an error callback can be called if the server does not return an image for whatever reason. As mentioned above, initialising the plugin is very similar to calling getJSON:

					$.getImageData({
						url,
						server,
						success: callback(image){},
						error: callback(xhr, text_status){}
					});

url

String

The URL of the image you want to fetch. Ideally PNG, JPEG or GIF, however, the server will accept other image types.

server

String

This is optional. It is the URL of the server you want to get the image data. Please see using your own server

success: callback(image)

Function

This function is called on successful fetching of the requested image. It receives one argument which is an Image() object that consists of the image and it's width and height as the properties width and height.

error: callback(xhr, text_status, error_throwdown)

Function

This function is called if the server returns an error code or takes more than 10 seconds (10000 ms) to execute. It receives two arguments which are xhr: the XMLHttpRequest and text_status: the status returned by the server (usually error or no_url).


Server Specification

$.getImageData provides a simple wrapper around the server-side code that allows callbacks to be added when the image has been loaded or if it fails. You can, however, directly query the server and get the same result. The server addresses are:

				http://img-to-json.appspot.com/

And for secure requests:

				https://img-to-json.appspot.com/

The call to the server can be made using an XMLHttpRequest to one of the above URLs. The server expects two things:

url

String

The URL of the image you want to fetch. Ideally PNG, JPEG or GIF, however, the server will accept other image types.

callback

String

The callback function to be called on server response. Default should be ?. This is to enable cross-domain JSON serving.

The server will respond with a JSON object consisting of data: the image data as a base64 encoded data URL, width: the width of the image and height: the height of the image.

Example request without the plugin or jQuery:

					// Image to be fetched
					var img_url = "http://farm4.static.flickr.com/3002/2758349058_ab6dc9cfdc_z.jpg?zz=1",

					// JSON callback function
			    callback = "image_loaded_callback",

					// URL of the server
			    server_url = "//img-to-json.appspot.com/?url=" + escape(img_url) + "&callback=" + callback,

					// Script container
			    script = document.createElement('script');

					// Set the URL to the JSONP and then append to document
			    script.src = server_url;
			    document.body.appendChild(script);

					// Callback function
					function image_loaded_callback(data) {

						// Create the image and set its src to the data URL
						var image = new Image;
						image.src = data.data;

						// When the image has loaded
						image.onload = function(){
							// Set its width and height
							image.width = data.width;
							image.height = data.height;

							// Insert it to the DOM (this is where you could put the image on to the canvas)
							document.getElementById('image_container').appendChild(image);
						};

					}

Server HTTP status codes

If the your request fails for whatever reason, the server will respond with the following HTTP status codes:

400 - Bad Request

This is usually because of a invalid URL has been sent or no URL has been sent.

413 - Request Entity Too Large

The image you are trying to fetch is too large. The limit for image size is 1MB.

415 - Unsupported Media Type

The type of the URL you are requesting is not supported by the server.

XXX - Anything else

If any other status code is sent, this is forwarded from the server that hosts the image.


Using your own server

If you don't want to rely on Google App Engine to server your images back as data URLs or if you would like to host a mirror server for use in the plugin then it is possible to run your own server. On GitHub in the server-examples folder you can find three different examples of the server written in Node.js, PHP and Python.


For documentation on the Node.js server, please go here.


If you are willing to run a mirror of the Google App Engine project, please email me at maxnull@maxnov.com.


Notes

1 Google app engine is free to use up to a point. If the daily usage exceeds their preset limits then the plugin won't work until the next day. Unless you decide to use your own server.


Attributions


License

The plugin is licensed in the same way as jQuery is: a dual MIT and GPL license. You can choose which license suits you best. For more information, please see:


Comments