IIIF Image API 3.0 conformance

Copy Markdown View Source

This guide documents image_plug's conformance to the IIIF Image API 3.0 specification — what we implement, what we deliberately don't, and the Compliance Level we target.

The reference is the IIIF Image API 3.0 specification and the IIIF Image API Validator. When this guide and the IIIF spec disagree, treat the spec as the contract and file an issue against image_plug.

Compliance level

image_plug's IIIF provider targets Compliance Level 2. Level 2 is the level most production servers (Cantaloupe, Loris, IIPImage) implement; it covers the full set of region / size / rotation / quality / format combinations that real IIIF clients (Universal Viewer, Mirador, OpenSeadragon) need.

We do not currently target Level 3 (which adds more granular size syntax and per-feature negotiation).

URL forms recognised

FormIIIFimage_plugNotes
<prefix>/<id>/<region>/<size>/<rotation>/<quality>.<format>The standard image-request URL. All five segments required.
<prefix>/<id>/info.jsonThe Image Information document. Returned as application/ld+json.
<prefix>/<id> (bare identifier)✅ (303 redirect to info.json)⚠️Currently rejected with :malformed_url. Roadmap: add the 303.

The <prefix> segment is fully configurable via the :endpoint option — "iiif/3" (default), "image", "" (mount-root), or anything else. The plug's outer mount path is also stripped before recognition via the :mount option.

Region segment

Formimage_plugNotes
fullNo Crop op produced.
square⚠️Parses as pct:0,0,100,100 (whole image). True centred-square requires source-aware computation; the lossy fallback is documented.
<x>,<y>,<w>,<h> (pixels)Ops.Crop{units: :pixels}. Out-of-bounds regions are clamped at apply time per spec §4.1.
pct:<x>,<y>,<w>,<h>Ops.Crop{units: :percent}. Resolved against actual source dimensions at apply time.

Size segment

Formimage_plugNotes
maxOps.Resize{upscale?: false} — no dimension constraints; the source size becomes the output size.
^maxOps.Resize{upscale?: true} — the ^ permits upscaling.
<w>,Width-only resize; height computed from source aspect.
,<h>Height-only resize.
<w>,<h>Distorts to exact dimensions (fit: :squeeze).
!<w>,<h>Fits within the bounding box, preserving aspect (fit: :contain).
pct:<n>Resize by percentage; mapped to Ops.Resize{size_pct: n}.
^ prefix on any of the aboveSets Resize.upscale?: true.

Rotation segment

Formimage_plugNotes
0Dropped by the normaliser.
Integer 1360Ops.Rotate{angle: n} (integer preserved).
Float 0.0360.0Ops.Rotate{angle: n} (float preserved).
!N (mirror-then-rotate)⚠️The angle parses correctly but the leading mirror is silently dropped — there is no Mirror op in the IR yet. Roadmap.

Quality segment

Formimage_plugNotes
defaultNo quality-related op.
colorTreated identically to default (the spec allows this).
grayOps.Adjust{saturation: 0.0}.
bitonalOps.Posterize{levels: 2}.

The IIIF spec lists default, color, gray, bitonal as the four base qualities. Servers MAY advertise more under extraQualities in info.json; we do not.

Format segment

ExtensionIR Format.typeNotes
jpg, jpeg:jpegAlways supported.
png:pngAlways supported.
gif:gifAlways supported (libvips bundled).
webp:webpAlways supported (libvips bundled).
tif, tiff:tiffGated on Image.Plug.Capabilities.tiff_write?/0 (most builds support it).
jp2:jp2Gated on Image.Plug.Capabilities.jp2_write?/0 (requires libvips built with libopenjp2).
pdf:pdfGated on Cairo support; advertised conditionally.

The info.json document advertises only the formats this build can actually produce.

info.json discovery document

The <id>/info.json endpoint serves the IIIF Image Information document. What we emit:

PropertyValueNotes
@contexthttp://iiif.io/api/image/3/context.jsonThe Image API 3.0 JSON-LD context.
idThe canonical service URLReconstructed from the request URL with /info.json stripped.
typeImageService3
protocolhttp://iiif.io/api/image
profilelevel2We're a Level 2 server.
width, heightSource dimensionsRead from the source resolver at request time.
extraQualities["gray", "bitonal"]Plus the always-supported default and color.
extraFormatsCapability-gated subset of ["webp", "tif", "jp2", "avif"]Always advertise webp; gate the others on Image.Plug.Capabilities.
extraFeaturesThe standard Level 2 setSee Image.Plug.Provider.IIIF.InfoJson source for the full list.

Response headers:

  • Content-Type: application/ld+json
  • Link: <http://iiif.io/api/image/3/level2.json>;rel="profile" (per spec §6)
  • Cache-Control: public, max-age=86400 (info.json is highly cacheable)

What we do not emit (Level 3 / Image API 4.0 features):

  • sizes and tiles arrays — the discrete-tile and pyramid-aware features used by IIIF zoom-image viewers.
  • service extensions — auth, search, content-state.
  • partOf, seeAlso, rights JSON-LD relations.

These are non-blocking for image-rendering clients but block heavyweight viewers like OpenSeadragon's pyramid mode. Roadmap.

Mounting the IIIF provider

forward "/iiif/3", Image.Plug,
  provider: {Image.Plug.Provider.IIIF, []},
  source_resolver: {Image.Plug.SourceResolver.File, root: "/var/lib/iiif"}

Or with a custom endpoint path:

forward "/imageserver", Image.Plug,
  provider: {Image.Plug.Provider.IIIF, [endpoint: "iiif/3"]},
  source_resolver: {Image.Plug.SourceResolver.File, root: "/var/lib/iiif"}

The full source-resolver story (file, HTTP, S3, custom) is in sources.md. The CDN-fronting story (CloudFront/Fastly/Cloudflare in front of the IIIF mount) is in cdn_origin.md — IIIF's URL grammar is just as cache-friendly as the four CDN providers.

Known gaps and roadmap

  • square region as true centred-square — needs source-aware computation in the parser, or a :square mode on Ops.Crop. Currently a pct:0,0,100,100 fallback (whole image).
  • !N mirror-then-rotate — angle parses; mirror is silently dropped. Add an Ops.Mirror op or a flag on Rotate.
  • <id> bare-identifier 303 redirect — currently rejected with :malformed_url. Spec-required redirect to <id>/info.json.
  • info.json sizes / tiles arrays — needed for IIIF tile-pyramid clients (OpenSeadragon, Universal Viewer's pyramid mode).
  • Authentication / Authorization API integration — IIIF Image API can sit behind the IIIF Auth API; not modelled.
  • sources.md — source resolution, including the S3 worked example.
  • cdn_origin.md — running image_plug as the origin behind a CDN; applies equally to the IIIF mount.
  • face_aware.md — face-aware crops; not used by IIIF (no gravity=face equivalent in the IIIF spec).
  • image_components's IIIF guide — the client-side story; how <.image provider={:iiif}> produces URLs this provider parses.