survos/iiif-bundle
A Symfony bundle for working with IIIF (International Image Interoperability Framework) resources, helping PHP applications expose and consume image API endpoints, manifests, and related metadata.
survos/iiif-bundle is a Symfony bundle for building and serving IIIF Image and Presentation API URLs. Its day-to-day value is narrow but real: it turns "we have identifiers for a few million archival scans on an IIPImage/Cantaloupe server" into "our Laravel app can render deep-zoom viewers and thumbnails without ever touching the bytes."
Minimal steps:
src/ before anything else. Release 1.0.0 ships with the note "not yet in survos mono", which means it has not been folded into the Survos monorepo — so there is no cross-package documentation, no worked example in the monorepo test suite, and no guarantee the surrounding ecosystem packages are version-aligned. Treat the source and DependencyInjection/Configuration.php as the reference docs.{scheme}://{host}/iiif/{id}/{region}/{size}/{rotation}/{quality}.{format}, you may not need the package at all. The package earns its place when you also want the Twig helper, the configured size presets, and the Stimulus/viewer glue.ServiceProvider, no config/ publish tag, and no auto-discovery. Register the underlying service class (or your own thin wrapper) as a singleton and map the bundle's configuration tree to a Laravel config file. See the Gotchas section — this is the main integration cost.identifier column (e.g. mss/0421), build a !400,400 size request, and put it in a Blade partial. This is a five-line win and validates your base URL, prefix, and server version assumptions before you commit to the viewer work.Check the server's info.json first (curl $BASE/iiif/$ID/info.json) — it tells you the API version, maxWidth/maxHeight, tile sizes, and supported formats. Everything downstream depends on those values.
Bind once, inject everywhere. Wrap the bundle's URL builder in a small IiifService of your own. The bundle's Twig function is not available under Blade, and wrapping it means you can swap Symfony services for a plain implementation if the bundle's lifecycle becomes a problem.
// config/iiif.php
return [
'base_url' => env('IIIF_BASE_URL'),
'prefix' => env('IIIF_PREFIX', 'iiif'),
'version' => env('IIIF_VERSION', 3),
'sizes' => ['thumb' => '!200,200', 'card' => '!600,600', 'full' => 'max'],
];
Keep identifiers out of the URL logic. Store the image identifier (and, for multi-tenant setups, the server host) as columns on the model. The service should accept an identifier and a size preset and return a string — nothing more. This makes it trivially testable with assertSame and no HTTP.
$model->thumbUrl = app(IiifService::class)->image($model->identifier, 'thumb');
Blade component for the viewer. Wrap OpenSeadragon or Mirador in an anonymous component that takes a manifest URL. The bundle's Stimulus controllers are Symfony UX-flavoured; either compile them through Vite as-is or re-implement the twenty lines of OpenSeadragon.init yourself. The latter is usually faster.
Manifests from Eloquent. Use the Presentation API builder (if present in src/, and check the API version it emits — 2.1 vs 3.0 manifests are not interchangeable) to compose a manifest from a collection + its ordered items. Cache the manifest JSON per collection with a version key; regenerating it on every viewer load is the most common performance mistake with IIIF-backed exhibit pages.
Warm and validate in a job. A queued job that fetches info.json for newly ingested identifiers gives you an early warning when a file is corrupt or missing on the image server, rather than a broken tile in production. Http::fake() the info.json in feature tests so the suite stays offline.
Don't proxy pixels. Your app emits URLs; the image server serves tiles. Anything that streams image bytes through PHP defeats the entire architecture.
Extension/Configuration semantics into a Laravel config file and instantiating services yourself. Budget an afternoon for the first integration.twig/twig into a Blade app. Harmless, but check composer.json — and prefer instantiating the URL builder directly to sidestep the extension entirely.quality=color/gray/bitonal and a different size grammar than 3.0 (max is not universal). The bundle's version setting must match what Cantaloupe/IIPImage actually advertises in info.json — not what the docs say.mss/0421 is legal in IIIF 3.0 but must be %2F-encoded for 2.x servers. The error is a silent 404, not an exception.maxWidth/maxHeight/maxArea. Requesting full/max on a server capped at 4000px returns a 400, and it will look like an auth bug when it is not. Read the caps at ingest and clamp your presets.curl and in the browser before debugging PHP.survos/iiif, the UX controllers, the fixtures) were not tested against this tag. Pin 1.0.0 exactly and avoid mixing with dev-main of adjacent Survos packages until the monorepo absorbs it.DependencyInjection/Configuration.php for the true config surface — the README likely lags.How can I help you explore Laravel packages today?