Over the past decade, browser vendors have introduced various new APIs that enable us as programmers to create richer and more fluent experiences. One of these is the getUserMedia
API, which enables access to the user's audio and video devices. However, it's still not quite there yet in terms of browser compatibility.
With this in mind, Adam Wróbel wrote JpegCamera, a library that takes into account the different caveats among browsers for interacting with user's camera and provides fallbacks for those cases where access to client's media is not supported.
In this article we'll see how by using JpegCamera, together with HTML canvas
element capabilities, we can build a clone of Instagram's Layout app:
The demo Layout-like application
The source code for the demo can be downloaded from Github.
The JpegCamera Library
JpegCamera allows you to access the user's camera as part of your application, gracefully degrading to a Flash fallback if the browser does not support getUserMedia()
.
The first step to is to include the necessary scripts in your project.
The library depends on the SWF Object and Canvas to Blob libraries, both of which come as part of the zip download from the project's Github page. However, in the same zip there's a with dependencies version of the script, which provides the same functionality as having the three scripts loaded in the page.
With this in mind, you can either include the three needed scripts.
<script src="/jpeg_camera/swfobject.min.js" type="text/javascript"></script>
<script src="/jpeg_camera/canvas-to-blob.min.js" type="text/javascript"></script>
<script src="/jpeg_camera/jpeg_camera.min.js" type="text/javascript"></script>
Or just go with the one script alternative.
<script type="text/javascript" src="js/libs/jpeg_camera/jpeg_camera_with_dependencies.min.js"></script>
For production environments, the later seem to be the way to go, unlike during development.
Once the library is included you can use the global JpegCamera object to check the camera availability, and choose how to manage the fallback if not.
If the access is granted, you can setup a listener for when the camera is ready with the JpegCamera()
constructor.
The JpegCamera()
constructor takes a CSS selector as an argument which should identify the container to be used for the camera stream.
The snippet below shows the code that does this:
(function() {
if(!window.JpegCamera) {
alert('Camera access is not available in your browser');
} else {
JpegCamera('.camera')
.ready(function(resolution) {
// ...
}).error(function() {
alert('Camera access was denied');
});
}
})();
This way, you can setup your application to only start once the camera is ready, or let the user know that they either require a different browser or need to enable camera access for the application.
Inside the ready
callback function, the device's camera resolution is passed as the first argument. This can be useful if the application we are building relies on the device's camera quality (i.e.: to make HD capture available or not).
Meanwhile the error
callback receives as an argument a string
message explaining what happened. If you need to show the user an explanation in case of an error, you can use the message the library supplies.
In addition to this, the JpegCamera API provides the following methods:
capture()
: This is the method that takes a picture. It returns the image itself as aSnapshot
object (the class thatJpegCamera
uses for images).show()
: Once you take the picture, theSnapshot
object that you obtain allows you to display the image in the page, by invoking itsshow()
method. The image will be displayed inside the same container you specified when initializing the camera.showStream()
: If a snapshot is currently displayed in the container,showStream()
hides the image and displays the stream.getCanvas()
: Takes a callback function as a parameter, which will receive as an argument thecanvas
element with the captured image.
Let's dive into an example application that illustrates what JpegCamera allows us to do.
Building the Application
The demo application emulates (sort of) what Layout does: it allows the user to take photos and generates new images by combining them. In our version, the combined images can be downloaded by clicking on them.
The application structure is based on the Module Pattern. This pattern gives us a couple of benefits:
- It allows to have a clear separation between each of the application components.
- It keeps our global scope clean by only exposing methods and properties that are strictly required by the others. In other words, we get to use private attributes.
You'll notice that I pass three parameters into the self invoked functions:
(window, document, jQuery)
And these arguments are received:
function(window, document, $)
The reason for passing window
and document
is for minification purposes. If we pass these as arguments, then each of them can be replaced for a single character. If we had just referenced these global objects directly, the minifier would not be able to substitute them with shorter names.
With jQuery
, we do it to avoid conflicts with other libraries that might also using $
as their main function (i.e.: Prototype).
At the top of the Layouts
and Custom
modules you'll see something along these lines:
if(!window.LayoutApp) {
window.LayoutApp = {};
}
This is for two reasons:
- We prevent the modules from generating errors in case we did not include the scripts properly in
index.html
. - We keep our global scope clean by making the modules part of a main one and only available for it once the application starts.
The application logic is divided into three modules:
- The App module
- The Layouts module
- The Custom module
These three modules together with our libraries must be included in our index.html
as follows:
Continue reading %Accessing the User’s Camera with JpegCamera and Canvas%
by Martín Martínez via SitePoint
No comments:
Post a Comment