AIR Forum: Web Camera Slide Show
I often find myself inspired by the questions that I encounter on the public AIR forums. Today I saw a question about using AIR to select a random image file from a user-selected location on disk. What piqued my interest was that the selected directory was to be populated by capturing images from a web camera.
What I want to build is a Sideshow program that randomly displays images in a folder. Then tie that in with a wi-fi camera that sends images to that folder. So, it needs to watch the folder for new files as it is running.
It occurred to me that while a wi-fi camera has the obvious benefit of being untethered, almost any web cam that could be registered with the system could also be used. The first task would be to activate and attach the web cam. For those coming to AIR by way of JavaScript, this isn’t something that just jumps out of the documentation. The key is to use the Video class and the Camera class.
// Start the web cam video
// Invisible to the user, but still capturable
webcam = new air.Video();
webcam.attachCamera( air.Camera.getCamera() );
webcam.visible = false;
window.htmlControl.stage.addChild( webcam );
An interesting aspect of this is that the web cam is attached and running, but set to be invisible. We’re interested in capturing the image from the web cam, but not interested in actually displaying the web cam itself. We can set the web cam as invisible for this, and still capture the pixel data for encoding.
To capture the pixel data itself, we use the BitmapData class, which contains a BitmapData.draw() method. You provide the BitmapData.draw() method the web cam object, and it will capture the current pixel data. To encode that pixel data, we can leverage the ActionScript 3 Core Library, which contains support for both JPEG and PNG. A dash of file IO sends the image to disk.
// Called incrementally to capture a web cam image
function doSnap()
{
// Setup the bitmap, encoder, file name and stream
var bmp = new air.BitmapData( 320, 240 );
var encoder = new runtime.com.adobe.images.JPGEncoder( 90 );
var jpg = null;
var now = new Date();
var stream = new air.FileStream();
// Capture and encode whatever is currently on the web cam
bmp.draw( webcam );
jpg = encoder.encode( bmp );
// Write the new JPEG image to disk
// Use time stamp for unique naming
stream.open( new air.File( dir.url + air.File.separator + now.getTime() +
'.' +
JPEG_EXTENSION ),
air.FileMode.WRITE ); stream.writeBytes( jpg, 0, 0 );
stream.close();
}
The JavaScript function setInterval() is used to incrementally capture an image from the web cam. The JavaScript function setTimeout() on the other hand is used to get a directory listing and select a random image to display in the “slideshow”. Since there may be a large number of images in the directory, we can use File.getDirectoryListingAsync() so we don’t interrupt the other operations.
// Called when the directory listing is complete
// Selects a random file to display
function doListing( e )
{
var index = null;
// Make sure there is a file to display
// TODO: Do not assume there is an image file available
if( e.files.length == 0 )
{
return;
}
// Generate a random index
// Make sure the selected file is a JPEG file
do {
index = Math.floor( Math.random() * e.files.length );
} while( e.files[index].extension.toLowerCase() != JPEG_EXTENSION )
// Set the selected image in the UI
document.getElementById( 'picture' ).src = e.files[index].url;
// Initiate the next refresh
// Note that "timeout" only executes once
setTimeout( doGrab, DISPLAY_TIMEOUT );
}
I like setTimeout() for this because it only gets called once after the specified interval elapses. Directory listing may take some time, so we can’t be sure that the operation will have completed in time. Using setTimeout() allows us to take care of what we need to for the slideshow, and then start another delay. The inverse might result in multiple images getting displayed in rapid succession, instead of an evenly spaced timing.

The full source for this little application is available, but as it turns out the person asking the question was planning to use Flex. I couldn’t just let that slide, so Flex source for the same functionality is also available. Might be a fun comparison for somebody. I personally found that for this project, managing Flex Timer instances was a little more tricky than JavaScript’s setTimeout() and setInterval().
November 1st, 2007 at 7:57 am
I get an error when parsing the supplied Application Descriptor using the Dreamweaver CS3 plug-in.
Actually, when I opened the AIR settings dialog, the Title field had “” in it, and I changed that to “Slideshow.” Upon inspection, when I changed that, it changed the xml to “” So this seems to be a problem with the plug-in, not with the descriptor.
A question, though. Am I required to have a webcam installed to use the software, or will it still display the images you included with the source, and any others I place in there? I ask this because I have no webcam, and when I start the program, after compiling it, all I see is a window with a scrollbar and a blue ? symbol in the middle.
November 1st, 2007 at 7:59 am
Whoops, it killed my xml references. Those are, in applicable order:
“[title/]”
and
“[title l=’Slideshow’ /]”
With “[” and “]” as replacements for the normal xml tag wrappers.
November 1st, 2007 at 12:13 pm
Ross,
Interesting note about the application descriptor - I’ll take a look.
Well … I guess it will display any images in the selected directory without a web cam. I hadn’t accounted for the possibility of not having a web cam as the original forum question specifically called out that requirement. That means that the application is going to start and look for a web cam, then not find one. I have no idea what the implications of this would be long term. To “fix” this, you could put a statement around the webcam bit to check first.
Hope this helps,
Kevin
November 2nd, 2007 at 7:49 am
I actually took a deeper look at the application descriptor myself. Turns out, the one provided has the [title] node set outside of the [initialWindow] node. Then, inside the [initialWindow] node there is a [title/], which is what the Dreamweaver plug-in seems to be displaying. When I changed that one, it displayed appropriately in the app-settings window.
Though it is interesting that when I initially changed it, it changed the one outside of the initialWindow.
November 5th, 2007 at 8:52 am
[…] webcam e airĀ […]
November 15th, 2007 at 2:12 pm
Kevin,
Sorry to post here, but the entry I’m posting about (http://blog.kevinhoyt.org/2005/01/18/drag-and-resize-with-flex/) has comments turned off.
The link to download the source code (http://www.markme.com/hoyt/files/drag-and-resize.zip) is returning a “Server not found” error.
Any way to relink this to a working server? Thanks very much,
-Pat
November 20th, 2007 at 11:00 am
Pat,
That’s strange - I don’t believe I’ve ever turned off comments. Until I just now went to turn them back on, I didn’t even know that was a feature. Something must have happened during a blog migration. I’ve turned on comments and updated the links. Thanks for finding that for me!
Just so you’re aware, that post was written a long time ago. The code itself will likely need some updating.
Thanks again,
Kevin