Obsolete / Unsupported Notice + Disclaimer

This experimental project was developed in 2004, and is no longer maintained nor supported - feel free to explore and tinker, download and use as you wish, but please be aware that this code is provided as-is and without support, etc.: "You're on your own!" :)


(Not Just Another?) Photo Viewer.

35mm photo viewer screenshot - Alpha skin

There might be only one way to look at photos, but there are an infinite number of ways to organize and present them.

This DHTML-driven browser-based app provides viewing of photos sorted by collection. A few different CSS-driven "skins" are also available to choose from. Thumbnails are dynamically displayed allowing for quick visual searches within a collection, and XML/XSLT functionality provides for more dynamic data sources and ease of updates.

Sound effects are also added for fun where supported, and are fairly simple to modify.

This viewer is best suited for smaller collections of photos, although it could easily enough be split across multiple pages or sections on a web server; the idea is that all photos are accessible from one actual HTML page, but this could be split to lower the page weight and load time.

Development and testing has been done under IE 5.0, 5.5 and 6.0, Netscape 7, Mozilla Firefox and Safari.

As a general notice, this project is in flux and functionality may change as bugs are found and fixed and features are added.



35mm photo viewer screenshot - White skin

The original intent was to have something simple for displaying photos, but over time the feature list has grown to include:

  • Funky design (well, as far as web developers go) with 3 different "skins"
  • Clean, gracefully-degrading search-engine-friendly code
  • Nifty effects (enhanced functionality, sound effects and transparency etc. where supported)
  • Hover-based floating thumbnails
  • Built-in "search" feature - also pre-populates and fires "automagically" if user is referred from a search engine
  • Bookmark-style functionality (users can make URLs to specific images)
  • XML/XSLT support (photos can be defined via XML, ease of updates etc.)


Get the goods.

35mm photo viewer screenshot - Inverted skin

Relevant Links


Revision History

Initial prerelease
Known bugs:
  • Safari/OSX - tab display offset, partially-repeating
  • ie:mac - several major display/functionality annoyances


Be informed.

A FAQ may be added to complement this section in answering specific issues, but the intent of the documentation section is to cover the overall features and functionality.

  1. Approach
    1. Markup Structure
    2. Bookmarking
    3. Default Behaviour
    4. Thumbnails
  2. Configuration
    1. CSS Skins
    2. Great SFX
    1. XML Structure
    2. XML Validation
    3. Client-side XML Transforms


Light on content, heavy on presentation.

Following the standards-based "separation of concerns," the markup for the data (collections, photos and descriptions, and titles) is minimalised, leaving the visual presentation (style) to CSS and additional functionality (search, thumbnails, sound effects) to be added by Javascript.

Updates and customization are also made easier due to the component/module-based nature of this approach.

Markup Structure

The photo viewer XHTML is structured to be both semantic and lightweight, while providing "hooks" for presentation via CSS without being excessive. The simplicity of the markup should make it easier to understand and modify.

<div class="collection">
 <h2 class="png">Everything Fishy</h2>
 <ul class="png scale">
  <li><a id="fish00" href="photos/everything_fishy/IMGP4017.jpg"><span>A first nifty photo description.</span></a></li>
  <li><a id="fish01" href="photos/everything_fishy/IMGP4022.jpg"><span>A second nifty photo description.</span></a></li>
  <li><a id="fish02" href="photos/everything_fishy/IMGP4026.jpg"><span>A third nifty photo description.</span></a></li>
  <li><a id="fish03" href="photos/everything_fishy/IMGP4045.jpg"><span>A fourth nifty photo description.</span></a></li>
 <div class="clear png"></div>

The collection class is a generic container element; the subsequent png classes are flags for PNG-based backgrounds handled by a Javascript object. The <h2> provides a nice title for the collection, and the following <ul> simply lists the photos themselves along with descriptions (nested in <span> tags so they can be hidden by CSS, but used by the presentational Javascript.)

Editing HTML is one option, but you can minimize the need for editing HTML if you choose to go with an XML-based template. The XML/XSLT section covers this in more detail.


Each photo is given a unique id so it can be "bookmarked" in the traditional sense (a unique URL pointing to a specific item or "anchor" within a page.) In the case of the photo with the ID fish00 and index.html being the URL, index.html#fish00 would point the browser directly to that photo (eg. it would be loaded.) A "Permalink" icon is provided next to each photo description, so people can click the link and add it to their favourites as they would any other.

The bookmark effect is achieved by Javascript, which simply parses the URL after the page has loaded, looking for an <a> tag with a matching photo ID and loading that photo if it is found.

Default Behaviour

Once loaded and initialized and if no bookmark is found, the viewer will choose a preferred photo based on a flag or select one photo at random from a group of photos. The viewer looks for items with a "default" class if no bookmark (that is, url "hash") has been specified. Photos can be marked with "default" in both XML and HTML, the latter being a class definition - eg. class="default". If multiple photos are given the default class value, one will be selected at random and displayed.


Photo thumbnails image

Thumbnails are displayed on hover of a photo item, giving a preview of the image in question. To reduce (in theory, at least,) page load time, one "strip" image includes thumbnails of all photos - reducing the number of browser requests that would be otherwise made for individual thumbnails. Image thumbnails are arranged vertically, and are put in a file named thumbnails.jpg within each image collection directory. The default thumbnail size is 64 x 48 pixels (width/height), but a few image and code modifications could be easily enough made to accommodate larger thumbnails.

A few alternate thumbnail types can be used, including "video" and "related content". The video type doesn't use the standard thumbnail JPEG, but instead looks for a GIF image based on the name of the photo being loaded. The GIF format of course allows for an animation to be used (ie., showing a few frames of the video) if desired.

The "related content" class, when specified, can be used for non-photo items such as links. One use could be adding a link to a related web site, the thumbnail being a screenshot of some of the site's content instead of a photo.

The following table defines the types of thumbnails used by class.

Item Class Item URL Thumbnail URL
Video some-video.mpg some-video_thumb.gif
Related Content http://www.example.com thumbnails.jpg*
(none, i.e. photo) some-image.jpg thumbnails.jpg*

* Cropping with vertical offset (handled via script) applies.

Here is some example HTML demonstrating use of the above types:

<!-- video, thumbnail URL is image/demo/fish/fish-movie_thumb.gif -->
<li><a id="fish08" href="image/demo/fish/fish-movie.mpg" class="video"><span>A video of some Jack Dempsey Cichlids (0.5 MB, MPEG)</span></a></li>

<!-- related content, thumbnail is within thumbnails.jpg -->
<li><a id="fish09" href="http://www.example.com" title="Related content: Everything about Fish" class="related"><span>Related content: Everything about Fish</span></a></li>

<!-- standard photo, thumbnail is within image/demo/fish/thumbnails.jpg -->
<li><a id="fish10" href="image/demo/fish/fish123.jpg"><span>A nifty fish photo.</span></a></li>

And the following are the equivalents for XML:

<!-- video, thumbnail URL is moving-the-general_thumb.gif -->
<video src="moving-the-general.avi" text="Moving 'The General', an Iridescent Shark (DivX 5 video clip)" />

<!-- related content, thumbnail is within thumbnails.jpg -->
<related src="http://www.example.com/" text="A related web site about fish." />

<!-- standard photo, thumbnail is within thumbnails.jpg -->
<photo src="fish123.jpg" text="A pair of Jack Dempseys hang out in their cave." />

"Gotcha" note: Thumbnail types which load from external files must be listed after all standard photos which use the thumbnails.jpg image, due to the way items are currently indexed - ie. the 1st photo item is the first image in thumbnails.jpg, the 2nd has an offset to the second image, etc. (A fairly simple future revision may be able to correct this.)

The photo viewer applies class attributes (ie. class="video") to the resulting collection item <a> tags to indicate the link type and resulting behaviour; it also is used to assign the icons for normal and hover states in the photo viewer. These classes are defined in the skin-specific CSS files, eg. alpha.css.


Change is good.

Don't like the skin? Change it. Want to split photos across multiple pages? Not a problem. You want a balloon pop sound effect when a thumbnail is shown? That might get annoying pretty quickly, but could be done easily enough.

CSS Skins

The presentation layer of the viewer is CSS-driven, and skins are set via script based on a predefined variable in default.js. Refer to this file for comments and details. Skins can be customised, but keep in mind there are some common styles set in the base.css file which apply regardless of the skin chosen; that is, skins are in addition to the base CSS. There are also some script tie-ins for PNG support under IE on Windows, but the supplied templates should give a good indication as to how this works.

Great SFX

This project makes use of another API for Javascript sound: "SoundManager." The API embeds a small (~3 KB) Flash movie which parses an XML file to define sounds and assign IDs, and provides simple methods for playing sounds - eg. soundManager.play('mySoundID'); would play the sound with the ID of mySoundID as defined in the XML file. This API requires Flash 5 and works on a number of (though not all,) browsers and platforms. More information on the SoundManager API can be found at its project page.


Template this.

"I don't want to have to write HTML!"

With XML, ideally, you don't have to. You can use simplified XML instead, as follows:

<collection title="Some Outdoor Photos" baseid="outdoor" basehref="pictures/outdoor/">
 <photo src="IMG01.jpg" text="Point Grey Secondary, Vancouver BC." />
 <photo src="IMG02.jpg" text="Looking West over the C-Train rails - Calgary AB." />
 <photo src="IMG03.jpg" text="Several thousand feet over the water just off the coast of Vancouver, BC." />
 <photo src="IMG04.jpg" text="A bike path heading East near the Barlow/Max Bell area, Calgary AB." />
 <photo src="IMG05.jpg" text="My favourite vacation spot - located in Vernon, BC." default="true" />
 <video src="moving-the-general.avi" text="Moving 'The General', an Iridescent Shark (DivX 5 video clip)" />

.. Leaving XSLT to handle the generation of valid, well-structured XHTML.

If your server supports XML/XSLT, you can take advantage of an XML-based photo template - reducing the effort required to make updates. An included XSL template will parse and spit out properly-structured XHTML, which is then interpreted by the photo viewer's presentational Javascript. There is also a PHP-based example provided which will dynamically generate the photo viewer page, transforming XML on-the-fly.

Even if you don't have server-side XML/XSLT support, you could still use XML locally and publish a static HTML page on your web site. Your browser can transform the photo XML into static HTML locally, which can then be copied and pasted into a photo viewer template page. This is detailed in Client-side XML Transforms.

XML Structure

The XML as shown above simply defines a list of photos and their associated descriptions, sharing some common attributes across each collection. Every collection element has an assumed baseid for bookmarking purposes, and a basehref which is the path prepended to each image URL.

The primary collection element attributes are as follows:

Defines the title of a photo collection.

Self-explanatory. Be descriptive, but not overly verbose; there is room for two lines of text, but one line will fit the design best. This value is placed into a <h2> element, so keep this in mind.

Example: title="Biking in Vancouver"

  • Take note of XML "gotchas". XML doesn't like certain "special" characters, eg. the Ampersand. To have an &, you need to use &amp; - eg. "Things & Stuff" becomes "Things &amp; Stuff" when defined in XML. The same goes for other characters such as those used in Latin and French; depending on encoding, you may have to use a numeric reference ie. &#232; for an è character. See this Wikimedia page for a basic HTML character/entity reference.
Defines a prefix for the unique ID assigned to each photo in sequence; eg. for a baseid of "outdoor", the resulting photo IDs would be "outdoor00", "outdoor01" etc.

These IDs are used in "bookmarking" photos (eg. the second "outdoor" photo) by making a shortcut to http://website/photos/index.html#outdoor01

Example: baseid="biking"

  • Use short IDs, i.e. one descriptive keyword summarizing the collection.
  • Use alphanumeric characters only (dashes are OK, but no spaces) as this value is written to an HTML id attribute.
Defines the path to the photos from the context of the photo viewer page.

The path is prepended and is relative to the current path. If the base of the photo viewer is /photos/ and pictures/outdoor/ is specified for the basehref, the resulting path for the first photo would be /photos/pictures/outdoor/IMG01.jpg.

Example: basehref="pictures/biking-vancouver/"

Example (same directory): basehref="/"

  • Potential "gotcha" note: Always leave a trailing slash, a "/", for the basehref attribute, even if the photos are in the same path (ie. no subdirectory.)

The photo XML structure also allows collections to be grouped into one or more pages:

 <page id="0">
  <!-- collection XML goes here -->
 <page id="1">
  <!-- collection XML goes here -->

Each page has its own icon in the main photo viewer control bar; the first page of items are shown by default.

To see an example of the XML structure, check out the demo page XML.

XML Validation

XML documents will not render unless they are valid; this means all tags must be properly closed, special characters such as ampersands must be encoded and the like. One easy way of checking your XML is to open it in a newer browser (IE 6, Netscape 7/Firefox 1.0 or Safari) and it will either render or display an error message with a description of the problem. If you try to transform invalid XML, you may get other less-descriptive error messages - so be sure to check it in a browser first.

Client-side XML Transforms

Even if you don't have support for server-side transforms, you can still take advantage of client-side XML/XSLT support built into most modern browsers. Some client-side XML transform pages are included which will attempt to transform the photo collection data and output nicely-formatted HTML results.

The idea is you can still use XML locally, copy the resulting transform output (photo collection HTML) into a static photo viewer template and have a valid, working page - without having to manually edit HTML.

XML/XSL templates and client-side transform utilities can be found under the templates directory, and vary slightly by browser.


Get in touch.

Comments, feedback, support, criticism, cool ideas, money.. you get the idea.

E-mail: Scott Schiller