Monday, February 6, 2012

How Do I Developed My Pixel Processing App Using Grails And HTML5 And Cloudfoundry?



It's been a long time I wrote a blog. Now I came up with explaining how does this simple web-app is working (thanks to Cloudfoundry!, so that others can see my app live). Play around with this web-app and try to figure out whats it doing, see the source code of the page, and have a idea of what is going on there.


(Note that the idea is taken from my favorite book Introducing HTML5 see here.)


In this blog I'm going to explain how does this small app is working. Well to be honest, the app main feature is provided by HTML5 canvas api's (which does the job of processing the given image's pixel, as you can see in the output of the app). Since I have developed this app in Grails, on the way I will explain the Grails goodness too....


So lets get started......


(Basic understanding of Grails,HTML5,Javascript will be good. But don't worry I will take my chances to keep it very simple)


The Basic Idea:
 The basic idea of this app is to get a image from the user (most preferably .jpg and .gif format) via an upload from. And the user can select what he wants, i.e as "XRay" or "Pencil Sketch format"! Depending on the user selection I (means my app) will process the image to that format!


HTML5 Goodness:


Iteration 0: 
 So I have decided my idea, but how do I implement it? Well as I mentioned before, I'm going to implement this in HTML5 canvas api's. So what is a canvas? Many definitions can be given for it, but I will stick to what Wikipedia say's:


"The canvas element is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images. It is a low level, procedural model that updates a bitmap and does not have a built-in scene graph." 


Fine, now I have decided  that I'm going to use HTML5 canvas api's for my job. So we will start writing a code using Canvas api's...... 


Before We Start Iteration 1:
I'm not sure how many of you understand what a canvas is from basic definitions given from Wikipedia. So I guess it would be good if you see some small code snippets of defining a "canvas" and working with it.


In HTML5 you can declare a canvas using this tag 


"canvas" (I have used quotes here because typing tag symbol making the blog post to rendering it!)


As the canvas in place, you can use JavaScript to get the 2D context like this:
var ctx =document.querySelector('canvas').getContext('2d')


Now you have access to the 2d context and now you can use API's to draw over it,that is easy by doing something like :


ctx.fillRect(10,10,10,10)


This will draw a rectangle on the canvas context. Hope this much intro to Canvas will do it for now.


Iteration 2:
As I have mentioned before, I need an image to convert into something that a user specify (as you can see in this site). But for time being, will keep it simple. Lets assume that the image location is given manually by the user.


As the canvas Api's provides a very cool feature in which the user/developer can interrogate individual pixels, this Api seems to be the best choice for our task, so lets use this.  


Once we load the image from the user disk we can get all the pixels from a 2d context, broken down into red,blue,green. This can achieved by this code : 


var ctx = document.querySelector(‘canvas’).getContext(‘2d’),
img = document.createElement(‘img’);
// wait until the image has loaded to read the data
img.onload = function () {
ctx.drawImage(img, 0, 0);
var pixels = ctx.getImageData(0, 0, img.width,img.height);
};
img.src = ‘userPhoto.jpg’; //users pointing to his/her photo


The important thing you need to look here is about the pixels variable. pixels is a CanvasPixelArray, which has the data properties. The data properties looks like : 


[r1,g1,b1,r2,g2,b2 . . . . ], 


where r1,g1,b1 makes up the first pixel and so on. Since we have access to the pixels from the image, we can really play with it!


Main Logic: 
In the xray display of the image, we need to invert the color of the each pixel(if your not getting what I mean by inverting, go now and play with my app, over here.), as this can be done easily by 255 minus the current value, as did here : 


for (var i = 0, n = pixels.data.length; i < n; i += 4) {
pixels.data[i+0] = 255 - pixels.data[i+0]; 
pixels.data[i+1] = 255 - pixels.data[i+2]; 
pixels.data[i+2] = 255 - pixels.data[i+1]; 
}


But why incrementing i=4? There are only three colors right, red,blue, green? No not actually, we have four, the fourth one is alpha, which is used for transparency purpose.


Now we have successfully inverted the pixels. So now we need to display it to the user like this: 


ctx.putImageData(pixels, 0, 0);


Thats it, the image will be inverted into the xray version! Cool isn't?


The soruce code of this section is over here(again this is the example taken from Introducing HTML5 book)


Grails Goodness:


Iteration 3:
Now we have the code working on the user's local disk. That is from the HTML5 Goodness section, we can place those codes in a file with a extension .html and run it in a user's browser locally. But how I achieved this web app? Using Grails goodness, is the answer. 


As you can see the home page, I have a upload form, which is achieved in Grails using this cool syntax: 
"g:uploadForm controller="image" action ="upload""

//other text goes here....
"/g:uploadForm"


(Aagin I have used quotes here because typing tag symbol making the blog post to rendering it!)



If you know Grails, you can see that, when the user clicks on the upload button, the action upload is called on the image controller. Here is the upload action : 


def upload = {
  def file = request.getFile('photo')
      session.file = [
          bytes: file.inputStream.bytes,
          contentType: file.contentType
      ]
                  if(params.userChoice == "X")
       redirect action: 'elsewhere'
    else if(params.userChoice == "P")
   redirect action: 'pencil'
  }


This looks very simple to Grails guys and for Grails girls too. But if you don't know Grails, here is what happening in the upload action in the controller:


1) Getting the file, which is the user input i.e photo


2) Converting those photos to bytes and then putting in the current "session". Hey why do I save in session? (will come back to this little later!)


3) Depending on the user choice, redirecting the user.  And thus displaying the result.


Now if the user have selected the xray option, then a elsewhere action is called. Yes your guessing it right, this elsewhere action will call a elsewhere.gsp file, which will be having the same code as I have explained in HTML5 Goodness, which will process the photo. 


But the job haven't done yet! In the HTML5 goodness I explained the code, which will work as the user is manually adding the image src address like this: 


img.src = ‘userPhoto.jpg’; //see this same code in HTML5 Goodness section


This wont work in our case, as user is uploading the image!(Read it again, uploading, got it?) Thats where session comes in handy. See again the upload action you can see that we are storing the user photo in his/her session (session will be alive for some time). 


Thats great! We have stored the photo's in the session, we have the pixel processing code in hand, but what do you think img.src will be equal to? So that we can point to the user uploaded photo and process on it? 


However this sounds complicated, we can achieve this by some more code like this: 


  def image = {
     if (!session.file) {
         response.sendError(404)
         return
     }
     def file = session.file
     session.removeAttribute 'file'
     response.setHeader('Cache-Control', 'no-cache')
     response.contentType = file.contentType
     response.outputStream << file.bytes
     response.outputStream.flush()
}


This is what happening in the above code: 
1)Check whether there is a file in the session, if not throw an error
2)Set the contentTypes,header and output the stream as bytes!


Now we are done, now we can place the img.src as :


img.src = "${createLink(action: 'image')}" //this will pick the image from the session!


Got why I'm using session?


Thats it we are done! We have our xray app on our hand ready to play! 


I have explained HTML5 and Grails goodness. But it will be very bad, if I miss to say "thanks" to Cloudfoundry. Well I'm not going to explain what is it. But I will give some suggestions of where you can start click here.


Conclusion: 


HTML5 Goodness + Grails Goodness + CloudFoundry = http://xray.cloudfoundry.com/


Have A Groovy day! Hope you have enjoyed it.


You can download the whole project source here.


Note: I'm very new to Grails and HTML5 hope I have kept it simple and understandable. Errors are common, if there are any errors, kindly say it. Comments are welcome. And also the pencil sketch technique I haven't explained it. You can see it from the source code, it is very similar to xray conversion.





No comments:

Post a Comment