Tuesday, March 19, 2024

Taking Photos from your HTML5 Web Apps

Taking Photos from your HTML5 Web Apps

It used to be that web applications were severely constrained by browser sandboxing. Aside from reading and writing cookies, front-end scripting languages like JavaScript and JScript were completely cut off from hardware. With more people going online using mobile devices than desktop computers, there is a real impetus for APIs that provide useful functionality such as geolocation, orientation, and of course, the ability to operate the camera and/or microphone. In today’s article, we’ll explore a number of ways to take photos from your HTML5 apps.

HTML5 Mobile Development Frameworks

There is a whole class of mobile development frameworks that allows you to code mobile apps using HTML, CSS, and JavaScript, as well as your favorite JS libraries. The frameworks then package your app for selected platforms so that it has access to device-level APIs that regular web applications would otherwise not. I recently wrote about several such frameworks: Apache Cordova/PhoneGap and Appcelerator Titanium and, more recently, about Adobe AIR and Sencha Touch.

With a lot of extra bells and whistles in addition to access to device-level APIs, Mobile Development Frameworks such as these have a lot going for them, so long as speed is not a critical factor. Supposing you choose to go with a framework, all have excellent documentation on how to work with the camera without having to worry about individual device APIs.

Here’s some sample code for Apache Cordova/PhoneGap:

navigator.camera.getPicture(onSuccess, onFail, {
    quality: 50,
    destinationType: Camera.DestinationType.DATA_URL
});

function onSuccess(imageData) {
    var image = document.getElementById('myImage');
    image.src = "data:image/jpeg;base64," + imageData;
}

function onFail(message) {
    alert('Failed because: ' + message);
}

The next code snippet takes a photo using Sencha Touch:

Ext.device.Camera.capture({
    success: function(image) {
        imageView.setSrc(image);
    },
    quality: 75,
    width: 200,
    height: 200,
    destination: 'data'
});

Using the getUserMedia API

The WebRTC project has developed some APIs that provide Real-Time Communications (RTC) capabilities to browsers and mobile applications. The getUserMedia API is one of these. It provides the capability to acquire audio and video from the device running the application. Performing additional operations such as sending the data over a network or storing it in a file must be accomplished using other APIs. As active participants in the WebRTC initiative, Google, Opera, Mozilla, and a few other vendors have implementations; the getUserMedia API has been built into their browsers since Chrome 21, Opera 18, and Firefox 17 respectively. Microsoft does not support getUserMedia, so it won’t work on Windows phones.

Testing for Support

When dealing with such a new technology, you should always test for support before trying to use it. Due to vendor prefixing, the best way to test for getUserMedia support is to use Modernizr. It even allows you to create the getUserMedia reference sans prefixing.

if (Modernizr.getusermedia){
  var gUM = Modernizr.prefixed('getUserMedia', navigator);
  gUM({video: true}, function(
  //...
}

Did I mention that the getUserMedia() method is not fully standardized? As it stands, Opera and Webkit differ slightly. The first input parameter tells the function what type of media we want access to. Opera takes an object, while WebKit, relying upon an older version of the spec, accepts a comma-delimited string. The second parameter in both cases are callbacks for success and error events.

var is_webkit = false;
if (navigator.getUserMedia) {
    //opera
    navigator.getUserMedia({video: true, audio: true}, onSuccess, onError);
}
else if (navigator.webkitGetUserMedia) {
    //webkit users
    is_webkit = true;
    navigator.webkitGetUserMedia('video, audio', onSuccess, onError);
}
else {
    //fallback code goes here
}

The is_webkit flag stores which browser the code is running in and handles these differences accordingly. (See next section!)

Capturing the Video Stream

The success event handler receives the video stream so that it can be assigned to a <VIDEO> element’s src attribute. Webkit requires that we first pass the stream to createObjectURL() before asigning it.

function onSuccess(stream) {
    var output = document.getElementById('output'); //a <VIDEO> element
 
    output.autoplay = true; //you can set this in your markup as well
 
    output.src = is_webkit ? window.webkitURL.createObjectURL(stream) : stream;
}

Taking a Picture

So far we’ve captured the video stream from the device’s camera, but that’s not quite the same as taking a still image. To do that, we need to set up a canvas element and draw an image from the video stream – basically taking a snapshot of the video at that moment in time.

function takepicture(videoOutput, width, height) {
      var canvas = document.getElementById('canvas'),
          photo  = document.querySelector('photo');
                       
    canvas.width  = width;
    canvas.height = height;
    canvas.getContext('2d').drawImage(videoOutput, 0, 0, width, height);
    var data = canvas.toDataURL('image/png');
    photo.setAttribute('src', data);
}

Conclusion

One drawback to the getUserMedia API is that browsers will usually ask your permission to proceed. That being said, if your app is running over SSL using the “https://” prefix, users’ decisions will remain in effect indefinitely so that they don’t have to grant or deny access every time they run your app. In an upcoming article, we’ll cover what you can do with your images after you’ve taken the perfect shot.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured