Creating Web Apps - The Camera API
Written by Mike James   
Sunday, 21 October 2012
Article Index
Creating Web Apps - The Camera API
Customizing

Using Image To Find Properties

 

What if you want to load the image and just discover some details such as its width and height. The file object only gives you the size of the file, its name and its MIME type, if known. To discover the size of the image you have to load it into something that understands the format. In this case you could use an Image object, for example, but there is a problem - the properties of the Image object are not available until the image file has been loaded and this is an asynchronous event.

So to find the width you might use:

var img=new Image();
img.src=fileURL;
img.onload = function() {
           alert(img.width );
          };

Of course, in a real program you might do something more useful with the information.

Loading The Photo To Canvas

 

We can also use the same technique to draw the photo directly to a canvas object.

<canvas id="myCanvas" width="578" height="400">

This is just a matter of loading the file into an Image object, as before and then when it is loaded rendering it to the canvas.

For example:

var img=new Image();
img.src=fileURL;
var canvas=document.getElementById('myCanvas');
var context = canvas.getContext('2d'); img.onload = function() {
   context.drawImage(img, 100, 100);
  };

You can now play around with the photo using the standard canvas drawing tools and save it back to a data URL in a format of your choice. 

Customizing the Button

The biggest problem with the HTML Media Capture API is that the button and file selection box it displays are not particularly suitable. They just don't tell the user that they are about to take a photo - they get involved in picking files.

In a well designed API we would have the option of changing the button's look, but this is not included in the standard. Indeed changing things that might be used to mislead the user is a security risk. The newer streaming API gets around the problem by asking for the users permission to use the camera, but in this case security is enforced by being obvious about what is happening.

To replace the button is difficult because different browsers use different security rules. You might think that a good way to do the job would be to hide the input element and then trigger its click event programmatically.

This works in Firefox, but not in Chrome.

The reason seems to be (there is no documentation) that Chrome refuses to fire the click event unless the button is visible.

However visibility can be achieved in more than one way and Chrome doesn't see to check to make sure that the button is big enough to be seen - so much for security. You have to conclude that it would be easier if Chrome just allowed the click to work while the button was hidden. As it is the imperfect security just makes life difficult for the programmer.

The simplest way to hide an element without actually setting it to hidden is to set its size to zero.

Now we will have a hidden snap input element, called hiddensnap and a button called snap that triggers the picture taking. You could use any element you care to design in place of the button.

<input type="file" id="hiddensnap"
           accept="image/*;capture=camera"
                 style="width:0px;height:0px" >
<button id="snap">
 Take A Photo Click here and use the camera
</button>

The JavaScript is more or less the same but the button's onclick is use to fire the input elements click event:

var snap = document.getElementById("snap");
var hiddensnap =
        document.getElementById("hiddensnap");
snap.onclick=function(e){
              hiddensnap.click();
           };

 

The input element then give the user the chance to use the cammera and raises its onchange event when the photo is ready for processing. The following JavaScript does this and also loads the photo into an img element and to the canvas as described previously:

hiddensnap.onchange=function(e){
 var file=e.target.files[0];
 var URL=window.URL|| window.webkitURL;
 var fileURL=URL.createObjectURL(file);
 var imgtag=
         document.getElementById("showPhoto");
  imgtag.src=fileURL;
 var img=new Image();
 img.src=fileURL;
 var canvas=document.getElementById('myCanvas');
 var context = canvas.getContext('2d');   img.onload = function() {
        context.drawImage(img, 100, 100);
        };
URL.revokeObjectURL(fileURL); };

 

This is not a perfect solution, but at least now the button that the user presses seems to have something to do with taking a photo. Unfortunately they still have to select the device they are going to use and there seems to be no way around this particular problem.

There is always the possibility that one of the browsers will add the rule that you can't raise a click event on an object that is of zero size, but this seems unnecessary.  The security is in the fact that the camera cannot be clicked without the user doing the clicking - and this should be sufficient.

Perhaps the Media Streaming API will be better.

If you would like the code for this article register with I Programmer and visit the CodeBin.

Related Articles

This article is one in a series on creating web apps:

 

 

 

CSS3 Rocks - Building a Custom CSS Button 

 

raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.

 

Banner


JavaScript Jems - Objects Are Anonymous Singletons

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way.  In particular, every object can be regard [ ... ]



JavaScript Canvas - Typed Arrays

Working with lower level data is very much part of graphics. This extract from Ian Elliot's book on JavaScript Graphics looks at how to use typed arrays to access graphic data.


Other Articles



Last Updated ( Monday, 21 January 2013 )