A “citable” deep-zooming image viewer

A couple weeks ago, when I was pulling together all the images for Textplot, a little text network-analysis project I’ve been working on recently, I ran into a familiar problem – I wanted a way to “cite” really specific parts of the images. This seemed especially important in this case because the images were enormous (about 20,000 pixels in height and width) and really dense – big clouds of tiny little words. And, in the blog post, I wanted to spend a bunch of time talking about really low-level, nitty-gritty details in the networks, often the locations of individual words – a kind of visual close reading. You can give “directions” for where to find things (“bottom left,” “right in the middle,” etc.), but that’s annoying for the reader, and most people won’t bother with it. What you really want is a way to quote the images in the way that you can quote a piece of writing – some way to pull out little snippets and build them into the narrative in a reasonably fluid, low-friction way. Sort of like the hard-linking feature we added to Neatline in version 2.3, which makes it possible to reference a specific record in the URL for an exhibit.

So, I decided to try to whip up something similar for static images, this time using OpenSeadragon, the venerable Javascript library for deep-zooming images. Along the way, I needed to solve a related problem – I had lots of images, so I wanted to find a way to write one little chunk of code that could handle all of them at once, ideally without having to monkey around with anything that I couldn’t just throw onto a s3 bucket along with the tile pyramids. After trying a couple of approaches, I ended up with a little project called osd-dzi-viewer, which is a barebones but workable solution – it’s a tiny static site generator that spins up a Backbone router that listens for routes like:

your.s3.bucket/#image-group/image

Where image-group is a directory on s3 (or GH pages, or whatever) that sits next to the generated index.html file, and image is a directory inside image-group that contains a filed called image.dzi and the corresponding tile pyramid under image_files. So, you might have a directory structure like this:

├── index.html
├── script.js
├── style.css
├── image-group
│   ├── image1
│   │   ├── image1.dzi
│   │   └── image1_files/
│   ├── image2
│   │   ├── image2.dzi
│   │   └── image2_files/
│   └── image3
│       ├── image3.dzi
│       └── image3_files/

Then, as the user pans and zooms around the image, the route gets updated with the current focus and zoom position, which makes it possible to link back to any given location. Eg, stuff like:

your.s3.bucket/#image-group/image/0.5615/0.4206/8.4324

Or, in the wild – here’s “napoleon” in War and Peace. The Javascript will also gracefully swap out the image on the fly if the image-group or image parts of the URL are changed. This makes it possible to link back to the same tab a bunch of times using target="_new" attributes on the anchors, even if you’re referencing more than one image – like this. This can be nice because it makes it easy for the reader to toggle back and forth without getting swamped with dozens of new tabs.

hard-link

Anyway, this is really simple code, and would be easy enough to adapt for projects that need more structure on the actual image pages (branding, navigation, metadata, etc). To build the viewer, just clone the repo, install npm and bower, and then run grunt compile:min, which writes the generated files to a _site directory. Or, just grab a pre-built archive from the releases on GitHub.