digital libraries,
web preservation,
books,
archives.

SZI: Tiled Images from ZIP Archives

2025-10-27 tags: openseadragon deepzoom iiif static digital library minimal computing

I've always been looking for simple solutions to serve digitized documents in static format, where the cost of maintaining an IIIF image server is prohibitive and I need something simpler to manage and preserve.

IIIF Level 0 is an option for serving static images in IIIF manifests without an image server. However, for large images this approach is inefficient, so tiling is required to serve partial images on demand.
There are ongoing discussions and experiments exploring how to bring static tiles to IIIF viewers, addressing a particular need: serving tiles from ZIP files, which offer significant advantages for management, portability, and storage. Reading remote ZIP content over HTTP using Range requests is now a standard practice, popularized by WACZ for serving web archives.

This GitHub discussion on IIIF Commons offers potential solutions for ZIP file-based tile delivery.
I already conducted an experiment using GeoTIFFTileSource with OpenSeadragon to access remote tiled TIFF files. Here is an example hosted on Cloudflare R2, featuring a 600MB TIFF file converted with VIPS.

Today I came across the SZI Format and the SZI Tile Source for OpenSeadragon.
Although not IIIF-based, this solution allows reading a remote DeepZoom .dzi file packaged in a ZIP file.

Let's test this approach by using a PDF file as source and converting its pages to tiled images.

To extract pages from a PDF, I use mutool from MuPDF, but many similar tools exist, such as pdftoppm from Poppler:

mutool draw -r 300 -o img-%d.png file.pdf

Next, use VIPS to assemble all images into a grid and convert to DeepZoom format:

IMG=$(ls *.png)
vips arrayjoin "$IMG" file.dz --across 8 --background "255, 255, 255"

Vips already generates a ZIP file file.dz, that only needs to be renamed as file.szi and served with a simple HTML like this one:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>SZI Tile Source Demo</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/openseadragon/5.0.1/openseadragon.js"></script>
  <script src="./dist/szi-tile-source-v0.6.1.umd.cjs"></script>
  <style>
    html, body {
      margin: 0;
      padding: 30px;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    #osd-szi {
      width: 100vw;
      height: 100vh;
    }
  </style>
</head>

<body>
  <div id="osd-szi"></div>
  <script>
    const sziUrl = 'file.szi';
    OpenSeadragon.SziTileSource.createSziTileSource(sziUrl).then(async tileSource => {
      const viewer = new OpenSeadragon.Viewer({
        id: "osd-szi",
        prefixUrl: "https://cdnjs.cloudflare.com/ajax/libs/openseadragon/5.0.1/images/",
        tileSources: [tileSource],
      });
    })
  </script>
</body>

</html>

This is a sample result — a scanned book served as a 200M .szi file: https://pub-0f1c9e6ddb92456a85802303778fa724.r2.dev/szi/index.html