« Waste not a watt ... | Main | The FOUR stages of Technology Use »

Chumby Photo Viewer Source code

I mentioned I created some software for the Chumby recently. I'm releasing portions of it for public consumption here. I'm not including the automatic e-mail uploader as that requires a custom component I'm not able to distribute. The php code just expects the images to be stored in a particular directory. It doesn't matter how they get there.

image

Chumby rule #1 though is that you must use non-progressive JPEG images. If you use progressive images, expect that the Chumby won't show them.

Chumby rule #2 is to keep the images small. I reduce the images to 640x480 (although the screen is 320x240) and compress them to 60% quality and am very happy with the images. You can play with the settings -- but you'll want to keep the images small so they download quickly. One of the settings (hard-coded in the Flash ActionScript) is the length of time between photos. Adjust that to suit your needs. It's eight seconds in the code I released.

The zipped package is here.

There's a key that is sent with every request to the server. The Flash ActionScript is hard-coded to the key ... just change it to whatever you want:

var apikey:String = escape("websitepassword"); // your web site password (must match what the web server expects)

The PHP has the same key and they must match.

If you don't want people to browse your photos directly, make sure you set up folder/directory permissions to prevent direct web browsing (through htaccess on an Apache web site for example).

Some snippets of the code I used follow.

var getImagesXMLComplete:Boolean = false; 

function getImages() {
getImagesXMLComplete = false;

txtStatus.text = "retrieving image list...";
this.getImagesXML = new XML();
this.getImagesXML.target = this;
this.getImagesXML.ignoreWhite = true;

this.getImagesXML.onLoad = function(success:Boolean) {
if (success) {
txtStatus.text = "success: " + this.firstChild.toString();
processImages(this);
}
getImagesXMLComplete = true;
}
this.getImagesXML.load(baseurl + "/getImages.php?" +
"startatfilename=" + lastfilename);
}



I parse the Xml this way (by grabbing the key data from the Xml file returned.)


function processImages(xml:XML) { 
var images:Array = XPathAPI.selectNodeList(xml.firstChild,
"/images/image");
if (images == null) { return; }

for(var i:Number = images.length - 1; i >= 0; i--) {
var photo:Object = new Object();
try {
photo.imageUrl = images[i].attributes.id;
photo.imageIndex = images[i].attributes.index;
trace("image: " + photo.imageUrl);
lastfilename = photo.imageUrl;
} catch(ex) {
txtStatus.text = ex.toString();
}
_photos.push(photo);
}
// trim if we've got too many photos collected
if (_photos.length > 200) {
_photos = _photos.slice(0, 200);
// reset if we've gone too far!
if (index > _photos.length) { index = 0; }
}

randomizePhotoList();
}



I added a debug mode to my chumby application:


var isDebugMode:Boolean = false; 
clipReminder.onMouseDown = function()
{
isDebugMode = true;
txtStatus._visible = true;
clipReminder._visible = false;
}

If the user touches the screen while the initialization is occurring, it puts the widget into a debug mode. The debug mode greatly helped me figure out what was going on as the emulator often worked when the Chumby did not. The debug mode shrinks the image to a small size and puts tracing text that I've scattered throughout the application on the Chumby's screen.


I randomize the list in place to keep memory use as low as possible:


function randomizePhotoList():Void { 
var i:Number = 0;
trace("randomizing");
for(i = _photos.length; i > 0 ; i--)
{
var rnd:Number = Math.round(Math.random() * i);
rnd = (rnd > i ? i : rnd);
var url:Object = _photos[i];
trace("swapping " + i.toString() + " with " +
rnd.toString());
_photos[i] = _photos[rnd];
_photos[rnd] = url;
}
}

If you have questions, feel free to email or post a comment.

Help support my web site by searching and buying through Amazon.com (in assocation with Amazon.com).