Repository navigation
feat: serve old map images from IIIF Image API services - #145
Merged
Merged
Conversation
Add src/iiif/delivery.ts with checkIiifDelivery, resolveIiifDelivery and IiifDeliveryError. Parsing of info.json and the request URL syntax are delegated to ol/format IIIFInfo and ol/source IIIF; the tile grid stays Maplat's HistMap grid. ol/format is kept external in the build. Tests cover every tile of the product grid (region, size, no missing or extra requests) for v2 level1, v3 level1, v2 level2 and level0 256 tiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… when it fails
- mapSourceFactory resolves delivery { type: "iiifImage" } on both the
map-setting path and the noload path, and re-applies the IIIF tile URL
function on the created source (OpenLayers regenerates it from url).
- IIIF maps are never registered to the tile cache.
- A map whose IIIF image cannot be used is reported as usable: false in
sourceLoaded and the other maps start normally. If the initial map is
not usable, startup falls back to the default map with a warning.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vice - New demo region "niigata": the 1920 Map of Niigata City from the National Diet Library, displayed directly from its IIIF Image API service (canvas 3). Alignment is provisional (6 control points). - A copy with a broken delivery URL shows that an unusable map does not stop startup. The new panel section lists recent old-map tile requests and whether the current map is cached. - e2e: the demo map is shown with tiles in the IIIF request form, no tile cache and no manifest request (served from fixtures). A live check against NDL runs only with MAPLAT_IIIF_LIVE=1. - README (en/ja) section on delivery and a CHANGELOG entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ternal - Level 0 services with 256 px tiles are served only when their scale factors are 1, 2, 4, ... without gaps; otherwise unsupported-level0. minZoom is never negative. - A missing or non-integer width/height (in info.json or in the expected size) is reported as size-mismatch instead of an OpenLayers error. - The record of unusable maps moves out of the MaplatApp declaration into a module-level WeakMap, so it no longer appears in index.d.ts. The demo reads the logged errors instead of Core internals. - README: only <maplat-app> reports unusable maps as usable: false; the MaplatApp sourceLoaded detail leaves them out. - Tests: every failure reason on both factory paths; the live check also covers the image service used by the demo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kochizufan
marked this pull request as ready for review
October 28, 2026 12:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Serve an old map's image straight from a IIIF Image API service. A map setting can carry
delivery: { type: "iiifImage", url }; Core reads the service'sinfo.jsonand requests tiles in the IIIF URL form instead oftiles/{mapID}/{z}/{x}/{y}.jpg.dist/is not rebuilt in this PR yet; abuild: rebuild distcommit is added right before merging.What changes
src/iiif/delivery.ts(new; not exported fromsrc/index)checkIiifDelivery(info, expected?)— pure check (no fetch) whether Core can serve the image:{ ok, version, level, tiling: "arbitrary" | "level0-256" }or{ ok: false, reason }.resolveIiifDelivery(delivery, expected, opts?)— fetchesinfo.json(credentials: "omit", 10 s timeout, 1 MiB limit) and returns atileUrlFunctionforHistMap(plusminZoomfor level 0 tiles). Tiles outside the image return the transparent PNG.IiifDeliveryErrorwithreason(bad-url,fetch-failed,timeout,too-large,not-json,unsupported-version,unsupported-level0,size-mismatch).info.jsonand building the request URL (region, size, quality, format) is left entirely to OpenLayers (ol/formatIIIFInfo,ol/sourceIIIF). Only the tile grid is Maplat's ownHistMapgrid; Core does not build IIIF URLs itself.src/source_ex.ts:mapSourceFactoryresolvesdeliveryon both the map-setting path and thenoloadpath. Because OpenLayers'UrlTileregenerates the URL function fromurl(whichHistMapfills in frommapID), the IIIF function is re-applied on the created source withsetTileUrlFunction.url/urlsnext todeliveryare dropped with a warning. IIIF maps are never registered with the tile cache (getMapCacheEnableisfalse).src/index.ts: a map whose IIIF image cannot be used no longer fails the whole startup. It is logged withconsole.error, left out of the rawsourceLoadedlist and reported as{ mapID, usable: false }in the element'ssourceLoadeddetail; the other maps start normally. If the initial map (startFromor the restored map) is not usable, startup falls back to the default map with a warning (this also covers maps dropped because the GL library is missing).vite.config.ts:ol/formatis external (likeol/source), so OpenLayers' IIIF code is not bundled.sizes-only level 0 and Image API 1 are reported as unusable for now.niigata— the 1920 Map of Niigata City from the National Diet Library (public domain), shown directly from the NDL IIIF image service (canvas 3; alignment is provisional, 6 control points). A copy with a brokendeliveryshows that startup continues; a panel section lists recent old-map tile requests and the cache status.delivery)". CHANGELOG: one line under Added.Tests
spec/iiif-delivery-grid.spec.ts: for every tile of every zoom of the grid built byHistMap_tin(including one ring outside the image), the requested region equals the tile's extent mapped back to image pixels and clipped to the image, the requested size equalsceil(clipped size / scale)and is at most 256, every tile touching the image is requested and none outside it. Run on fourinfo.jsonfixtures: NDL (v2, level 1, 1024 tiles), iiif.io example (v3, level 1, 512 tiles), Stanford (v2, level 2) and a hand-written level 0 with 256 tiles. Fixed URL expectations are listed in the spec.spec/iiif-delivery.spec.ts: the check's cases and the resolver's failure modes (URL form, fetch failure, timeout, size limit by header and by streamed bytes, non-JSON, v1, size mismatch,@idmismatch warning,minZoom).spec/iiif-source-factory.spec.ts: both factory paths with the same fixtures (tile URL on the created source with amapID, no tile cache,url+delivery, failures asIiifDeliveryError).spec/iiif-unusable-source.spec.ts: startup with an unusable IIIF map, including when it is the initial map.e2e/iiif-image.spec.ts: the demo region with NDL responses served from fixtures — map shown, every tile request in the IIIF form, not cached, no manifest request.e2e/iiif-live.spec.ts: 5 requests to NDL (info.json and 4 tiles); runs only withMAPLAT_IIIF_LIVE=1, skipped in CI.🤖 Generated with Claude Code