Creating a tiled zoomable image with OpenSeadragon and vips#
The San Francisco Microscopical Society has some extremely high resolution scanned images - one of them is a 1.67GB PNG file with a 25,088 × 17,283 pixel resolution.
I wanted to display these in a browser using a zoomed interface, without needing to load in that whole file.
OpenSeadragon looked like a good fit for this:
An open-source, web-based viewer for high-resolution zoomable images, implemented in pure JavaScript, for desktop and mobile.
Creating the tiles with vips#
The first step in using it is to split the source image up into a set of tiles.
OpenSeadragon offers a range of options for doing this. After investigating a few the one that worked best for me was vips, with its vips dzsave command.
Installing this on macOS with Homebrew:
1brew install vips
Once installed you can split a source image into tiles like this:
1vips dzsave Miniature_Victorian_Slide_Collection.png \2 Miniature_Victorian_Slide_Collection
This command runs really quickly: it took just a few seconds, and Activity Monitor showed it using more than 600% CPU, so it is clearly optimized to make full use of multiple cores.
This command creates an XML file called Miniature_Victorian_Slide_Collection.dzi
defining the zoomed tile set, and a folder called Miniature_Victorian_Slide_Collection_files
containing thousands of smaller tiles, arranged in a hierarchy.
1% find . | grep Miniat | wc -l2 5233
That’s a LOT of files. They were each around 256 × 256 in resolution - I decided to see if I could make them bigger and reduce their number.
I used the --tile-size
option to do this:
1vips dzsave Miniature_Victorian_Slide_Collection.png \2 Miniature_Victorian_Slide_Collection-tile-size-512 \3 --tile-size 512
This created a more manageable 1,343 files, totalling 25.2MB.
Implementing the viewer#
Here’s the minimal HTML I figured out to create a zoomable viewer that takes up the full browser viewport:
1<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">2<style>3#openseadragon1 {4 width: 100vw;5 height: 100vh;6}7body {8 margin: 0;9 padding: 0;10}11</style>12
13<div id="openseadragon1"></div>14<script src="https://cdn.jsdelivr.net/npm/openseadragon@3.1/build/openseadragon/openseadragon.min.js"></script>15<script type="text/javascript">16var viewer = OpenSeadragon({17 id: "openseadragon1",18 prefixUrl: "https://cdn.jsdelivr.net/npm/openseadragon@3.1.0/build/openseadragon/images/",19 tileSources: "Miniature_Victorian_Slide_Collection-tile-size-512.dzi"20});21</script>
Saving this as index.html
in the same folder as the .dzi
file and then serving it like this let me start zooming and interacting with the tiled image:
1python3 -m http.server