Accessing the Camera in a Windows 8 Metro Style App using HTML and JavaScript

Overview

I have recently been coding a Windows 8 Metro Style App using the new Windows 8 Release Preview bits and Visual Studio Express 2012 RC.  The app is going to be a retro shooter that takes advantage of HTML5 Canvas for the main game engine and then several Windows 8 Metro Style App Features.

One of the things I wanted to do in the game was to keep Player Profiles.  These profiles track player high scores, player names and a player avatar.  Eventually these high scores could be used in a leaderboard running in the cloud. 

Player Name and Avatar

 

I thought it would be neat to let players take a picture of themselves for their Avatar by accessing the webcam.  Fortunately for us WinRT makes this super easy to use.  We can even pull up prebuilt camera capture UI by using the built-in Windows.Media.Capture API’s.  If you are an existing Windows Phone Developer this may remind you a lot of Windows Phone Development Tasks – something I absolutely loved. 

Features like camera timer, settings, and  even picture cropping are all done for us via the Windows.Media.Capture.CameraCaptureUI.  For those looking for more control you also have the ability to call into Windows.Media.Capture.MediaCapture.  You won’t get a default UI with MediaCapture but you do get full control of the streams.  MediaCapture is also a way to record Audio streams in your app.

Here is what the default Capture Capture UI looks like when using the cropping tool:

Camera Capture Cropping Tool

After cropping the photo to my liking and tapping the OK button my new Avatar is automatically set.  The new Avatar Image is automatically scaled correctly thanks to the predefined CSS styling we have created.

New Avatar Picture

 

Sweet!

 

Declaration and Initialization

One of the joys of doing Windows 8 Metro Style development with HTML and JavaScript is that it feels like Web Programming.  In fact my entire game header is done using normal <div> tags and CSS Styles.  Inside of my default.html file I defined the following header to display the player score, level, name and avatar picture:

 <div id="divGame">
         <div id="txtScore">Score: 0</div>    
         <div id="txtLevel">Level: 0</div>
         <div id="divPlayer">
              <div id="txtPlayerName">Player1</div>
              <img id="imgPlayer" src="/images/helmet.png" />
          </div>
 <div>  

 

I then defined a CSS Style for the Avatar Picture using it’s imgPlayer id.

 #imgPlayer {
     max-width: 100px; 
     max-height: 50px;
     float:left;
     margin-right:10px;
  
 }

 

The Windows Library for JavaScript (WinJS) gives us a way to create a Windows 8 AppBar easily by just a few lines of HTML (more on WinJS Controls later).  By opening the AppBar and tapping the cmdCamera button our players will get the option to take a new Avatar picture.

 <div id="AppBar" data-win-control="WinJS.UI.AppBar" data-win-options="">
        <button id="cmdHome" data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdHome',label:'Menu',icon:'home',section:'selection',tooltip:'Menu'}">
        </button>
       <button id="cmdCamera" data-win-control ="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdCamera',label:'Cadet Photo',icon:'camera',section:'global',tooltip:'Change Cadet Photo'}">
        </button>
      <button id="cmdName" data-win-control ="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdName',label:'Cadet Name',icon:'url(images/accept.png)',section:'global',tooltip:'Change Cadet Name',type:'flyout',flyout:'nameFlyout'}">
        </button>
 </div>

 

All of the AppBar buttons tap events are handled using standard JavaScript EventListeners:

 //AppBar Commands
         document.getElementById("cmdCamera").addEventListener("click", capturePhoto, false);
         document.getElementById("cmdName").addEventListener("click", showCadetNameUpdate, false);
         document.getElementById("cmdHome").addEventListener("click", showMenu, false);
         document.getElementById("submitButton").addEventListener("click", updateCadetName, false);

That’s it! We now have a working Game Header and AppBar for our game.  When a player clicks on the Camera Button we will invoke a call to the capturePhoto function.

 

Opening the Camera Capture UI

capturePhoto is where the magic happens.  The first thing we do is make a call to WinRT using the Windows.Media.Capture namespace.  This gives us a reference to CameraCaptureUI where we can set default properties.  For my game I am telling the camera to use a 16x9 aspect ratio and lock to the photo mode.  If I wanted the user to capture video I could easily do this as well by using Windows.Media.Capture.CameraCaptureUIMode.video.

 //WinRT Camera API
     function capturePhoto() {
         try {
             var dialog = new Windows.Media.Capture.CameraCaptureUI();
             var aspectRatio = { width: 16, height: 9 };
             dialog.photoSettings.croppedAspectRatio = aspectRatio;
             dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).then(function (file) {
                 if (file) {
                     imgPlayer.src = URL.createObjectURL(file);
  
                 } else {
                     //No Photo captured
                 }
             }, function (err) {
                 displayError(err);
             });
         } catch (err) {
             displayError(err);
         }
     }

This is where you will start to see all of the Async goodness inside of WinRT.  The Camera Capture UI  will run asynchronously while it awaits the user to take a picture.  I handle the callback by invoking a JavaScript Promise using the then keyword.  The promise will call a function when the user takes a photo and if there is an object it will set the source of my imgPlayer tag to be that file.  Those of you familiar with Web programming will recognize the URL.createObjectURL call so that my <img> tag knows where to reference the new source file.

 

Conclusion

Hopefully you have seen how easy it is to access the WebCam on Windows 8 now thanks to WinRT and the Windows.Media.Capture API’s.  As Always - if you are currently working on a Windows 8 app I would love to hear about it!

You may also want to check out my previous Windows 8 Metro Style Development Tips: