Monday, January 26, 2009

Clientside image processing with Javascript & Gears

We all know the problem on processing images on the client side, you don't have access to the images on the local hdd. For some pages like Flickr or other photoservices it's alright because they're interested in the fullsize pictures. But what if you want to decrease the size of the pictures before uploading them, to offer the users an increased speed or for example you also would like to add additional functionality like processing the color scheme or croping image parts without requiring an upload first. That's the requirement I had, building a photo uploader that can scale and compress the picture before uploading them. So perhaps air would have been a possibility to fullfill that requirements but I searched a possibility to solve that via javascript.
So I thought that perhaps Google Gears could solve my problem. Looking through the api reference I read something about a Canvas Api. Unfortunately this api is anounced but not released so far. In the release notes about version 0.5 I read -
Local Server :"Added the captureBlob() method.". So I started to play around with gears a bit and here is my solution to the problem:

First of all the gears components we need:
var desktop = google.gears.factory.create('beta.desktop');
var localServer = google.gears.factory.create('beta.localserver');
var store = localServer.createStore('test-store');
store.enabled = true;
var context = $('#can').get(0).getContext('2d');


Bind the openfiles call somewhere:

$('#selectFiles').bind('click', function(){
desktop.openFiles(ImageEditor.openFilesCallback);
}

So let's take a look at the callback:

openFilesCallback: function(files) {
try {
if(files.length > 0){
store.captureBlob(files[0].blob, 'http://example.com/images' + files[0].name, 'image/jpeg');
$('#someImage').attr('src', 'http://example.com/images', files[0].name);
context.drawImage($('#someImage').get(0), 0, 0);
context.scale(0.5, 0.5);
$.post('http://example.com/images/some.php', {test:context.canvas.toDataURL('image/jpeg').substring(context.canvas.toDataURL('image/jpeg').indexOf(',') + 1)}, function(){}, "html");
}
}catch (e) {}
}


The open files callback is getting an array of maps as parameter containing the name and the blob data.
The blob data can be captured to the local server with the additional possibility of setting the content type. After that it can be served via the same domain as the main page as source of an image tag. Now just import it and edit your image using the features of the canvas element. The last clue is now to use the to dataurl method and export the image as base64 encoded string. Now you can easily send this string to your server in a xhr post request without all that file submitting problems... Finally you only need to base64decode it on the server and save it back to the file system.

Unfortunately this all still doesn't work in IE, but that's a fact everybody is used to. Perhaps ExCanvas can soon offer this possibilities...
I'll keep you in the loop if there is anything new and will soon post a full implementation example.

No comments:

Post a Comment