You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make dezoomify-core the single implementation of format discovery and tile planning, use it from the native application and a new browser application through WASM, then remove the duplicate JavaScript dezoomers.
The first foundation phase shipped in dezoomify-rs 2.19.0. dezoomify-core is pure Rust with no I/O, async runtime, image decoder, or filesystem dependency. It already provides the discovery state machine, catalog and level model, registry, known and adaptive tile plans, and tile-processing recipes.
The remaining work is deliberately split into small parity, porting, and product-integration steps below.
Rules for this migration
Keep dezoomify-core host-neutral. Fetching, CORS/proxy policy, decoding, assembly, persistence, and UI stay outside the core.
Add a deterministic fixture before changing or deleting each legacy branch.
For every live-site audit below, verify automatic detection, metadata dimensions, and at least one maximal-level tile. Record the date and result in the PR.
If a site is dead and no replacement deployment exists, delete its special-case code, deterministic fixture, live case, and documentation in the same PR.
Do not classify a protocol as dead solely because one site returns 403/500 or blocks the hosted proxy. Keep protocol fixtures when another deployment or direct endpoint still works.
Port site-page scraping as a discovery adapter that returns a deferred Zoomify/DZI/IIIF/generic input; do not duplicate an existing tile protocol.
For a new format, declare one co-located DezoomerSpec and add it to the canonical Rust registry; use an immediate program or ordered DiscoveryRoute table according to its resource flow.
Do not remove the legacy web app until the blocking browser parity suite passes against the deployed WASM build.
1. Audit and shrink the legacy JavaScript app
1.1 Remove already-orphaned test data
The PFF, old pre-IIIF Micrio, and Mnesys handlers were removed after no live deployment could be found. Their fixtures remain.
Delete the PFF requestType=1 and requestType=2 fixtures and the unused fixture-server route.
Delete the old Micrio api/getTilesInfo fixture. Keep current Micrio-as-IIIF fixtures.
Delete the Mnesys p.xml fixture.
Prove whether mirador.html, the CONTENTdm record HTML, and the Memorix detail HTML/API pair are reached by any test; delete each file that is not reached.
Replace the one shared issue_81 JPEG used as a generic response with a minimal named fixture, then delete the other 62 unreferenced tiles and metadata.
Update the README's live-tested-site list from the actual live-test table.
Test the University of Bern biblio.unibe.ch/web-apps/maps/zoomify.php branch.
Test the Paris specialized libraries bspe-p-pub.paris.fr/MDBGED/zoomify-BFS.aspx branch.
Retest the National Gallery of Victoria page branch and retain its existing live case.
Test the artandarchitecture.org.uk/images/zoom branch.
Test Flash zoomifyImagePath page extraction with a deterministic fixture.
Test HTML5 showImage page extraction and <base href> resolution; retain the existing fixture.
Test the Fluid Engage accessnumber to XMLBroker.new.php rewrite.
Test the OpenLayers .ete-openlayers-src extraction.
Test OpenLayers zoomifytileservice and tilesUrl extraction.
Test iframe recursion to a Zoomify child page.
Test <url>...</url> extraction.
Retain direct ImageProperties.xml, direct TileGroup URL, tile-group arithmetic, and full-resolution-only NUMTILES fixtures even if all site-specific branches are removed.
Attempted the current Museo del Prado data-pyr page; its hosted target returns HTTP 403, so the deterministic Las Meninas fixture remains and the live case is removed.
Test the British Library Viewer.aspx to Proxy.ashx rewrite.
Test the Polona JSON API conversion.
Retest the Bibliotheques specialisees de Paris rewrite and retain its live case.
Find a current National Library of Australia deployment for the /view to /dzi rewrite and special tile origin, or remove that branch.
Test the World Digital Library-style view/<group>/<index> extraction.
Test zoom.it and zoomhub.net content detection.
Test generic page extraction of .xml, .dzi, and dzi= links independently of Seadragon.embed.
Test iframe recursion to a DZI child page.
Retain direct DZI, direct PNG/JPEG tile input, legacy Seadragon.embed, and overlap-placement fixtures regardless of site cleanup.
1.4 Test every unverified IIIF/site-adapter branch
Audited Koninklijke Verzamelingen: the current deployment no longer exposes Memorix; removed the stale kha mapping.
Retest Beeldbank Groningen (gra) and retain its live case.
Audited RHCR Rijnstreek: the current deployment no longer exposes the mapped Memorix service; removed the stale srs mapping.
Live-test SALHA (sha) direct detail mapping.
Live-test Archief Zaanstad (zaa) direct detail mapping.
Live-test Regionaal Archief Zutphen (szu) direct detail mapping.
Live-test Noord-Hollands Archief (ranh) direct detail mapping.
Audited Nationaal Archief: the current deployment no longer exposes the mapped Memorix service; removed the stale naa mapping.
Test former Gahetna thumbnail parsing.
Test RKD thumbnail parsing and its separate result host.
Retest <pic-mediabank> detail and gallery API discovery; retain the Historisch Archief Midden-Groningen live case.
Test the embedded server: "..." JSON branch.
Retain direct TopViewer JSON and linear tile-number fixtures even if institution mappings are removed.
1.6 Test remaining site-specific branches
Arts & Culture: add deterministic fixtures for metadata discovery, URL signing, encrypted tile processing, and unencrypted passthrough; retain the live case.
Arts & Culture: test the /g.co/arts/ short-link entry form.
krpano: test a current Hyper-Photo deployment or remove the hyper-photo.com/hyperpano hint; retain the krpano live case and protocol fixtures.
XLimage: test the KBR viewer-page prompt/rewrite branch separately from direct ?cmd=info support.
Hungaricana: add fixtures for imagepath, inline files/images, and files_url page discovery; retain direct ECW and live gallery cases.
pnav: retain deterministic Pushkin coverage and the Ethnographic Museum live case; do not delete the protocol because catalog.shm.ru is blocked.
ArcGIS MapServer: add a live case for the Cartesius/NGI cached service from [new site support] cartesius.be #987; retain cached, viewer URL, global coordinate, query-token, and uncached-service fixtures.
Generic: add deterministic cases for padded placeholders, non-256 tiles, smaller edge tiles, the 999/1000 search boundary, one-dimensional grids, an absent origin tile, placeholder images returned instead of 404, and encoded braces/query parameters.
Automatic selection: add focused tests for precedence, iframe recursion, repeated/cyclic frames, and a match found only in a child frame.
Full assembly: add at least one deterministic output-pixel test per tile-layout family because most browser tests currently assert generated URLs and only fetch tile (0,0).
1.7 Run and classify every current live target
Run each case individually so one flaky host does not hide another result. A passing generic protocol target does not validate a separate site-specific branch.
Arts & Culture.
National Gallery.
Memoire des hommes (removed from live targets: current IIIF metadata advertises a private backend and the first tile is unavailable).
London Museum collections.
Philadelphia Museum of Art.
Liechtenstein Collections.
National Gallery of Victoria.
CSNTM manuscripts.
Austrian National Library.
Direct Memorix TopViewer.
Beeldbank Groningen.
Historisch Archief Midden-Groningen.
BLB Visual Library Server.
Hungaricana postcard gallery.
Oklahoma State Digital Collections.
University of Washington Mirador.
krpano.
Bibliotheques specialisees de Paris.
Academia Sinica Bronze Rubbings.
FSI Viewer.
HNG IIPImage.
Uffizi XLimage.
ArcGIS World Imagery WMTS.
BLB generic tile template.
Alabama Maps LizardTech.
OpenSeadragon Zoomify example.
National Library of Israel (removed from live targets after HTTP 403 from the current IIIF endpoint; retain IIIF support).
National Library of Scotland Auchinleck.
National Library of Scotland map-view.
Westchester County Archives (removed from live targets after a CONTENTdm API timeout; retain CONTENTdm support).
Pushkin Museum pnav (removed from live targets after the current page timed out before exposing metadata; retain pnav because another deployment passes).
Ethnographic Museum pnav.
Make the live job report failures prominently even if it remains non-blocking.
2. Port legacy tests for formats already in dezoomify-rs
Port deterministic behavior first. Keep site adapters separate from core protocol parsers. Tests already covered by the same Rust fixture/live target do not need to be duplicated: Arts & Culture live, generic fixture/live, HNG IIPImage live, and krpano live.
2.1 Cross-format selection
Build a fixture-backed Rust discovery-driver test that runs automatic discovery and asserts the selected canonical format for every supported format.
Assert candidate precedence for ambiguous inputs, including Zoomify tile URLs and content-driven IIIF/DZI inputs.
Assert immediate and ordered declarative multi-resource discovery through the common operation, including URL mapping, follow-up resources, failure handling, cycles, and limits.
2.2 Zoomify
Port the direct 512x512 ImageProperties.xml fixture and final TileGroup0/1-1-1.jpg assertion.
Port HTML <base> plus showImage discovery as a deferred Zoomify adapter test.
Port the full-resolution-only NUMTILES=280 regression; all 280 full-resolution tiles must remain in TileGroup0, including 6-16-6.jpg.
Port the NGV object-page live test.
Port the OpenSeadragon Zoomify example-page live test. (Cancelled: the current viewer references a deleted ImageProperties.xml path; retain the direct Zoomify live test.)
Retain the new Rust tile-URL-to-sibling-metadata unit and end-to-end tests.
2.3 Deep Zoom/DZI
Port the direct sample.dzi fixture and final sample_files/9/1_1.jpg assertion.
Port PNG tile URL input and assert sibling .dzi discovery.
Port .jpeg tile URL input and assert sibling .dzi discovery.
Port legacy Seadragon.embed(..., "legacy.xml") discovery as a deferred DZI adapter test.
Port the overlap=1 destination assertions (0,0), (255,0), (0,255), (255,255) as an end-to-end DZI test.
Port the Prado data-pyr fixture, including dimensions, tile size, overlap, maximum level, and first tile URL.
Port the Bibliotheques specialisees de Paris live test.
Port the Academia Sinica Bronze Rubbings live test.
2.4 IIIF
Port the Image API 2 fixture, native PNG quality choice, and edge tile URL.
Port Mirador ?manifest= query extraction as a deferred IIIF adapter test.
Port Universal Viewer #?manifest= fragment extraction as a deferred IIIF adapter test.
Port <micr-io id> extraction as a deferred IIIF adapter test.
Port the Image API 3 default-quality/JPEG fixture as an integration test.
Port all four ONB entry forms: viewer root, viewer page, direct Presentation 3 manifest, and RepViewer URL.
Port the explicit returned edge dimensions regression for a 600x384 image.
Port the private/RFC1918 metadata ID regression; generated tiles must use the public info.json base.
Port the same-host default-port regression; generated tiles must not retain the incorrect :80 origin.
Port CONTENTdm record-to-API-to-info.json discovery.
Decide and document whether plain-image-only Presentation manifests remain supported by Rust or match the legacy rejection; add the chosen regression.
Port National Gallery page extraction.
Port London Museum bare IIIF service-root extraction.
Port Philadelphia Museum escaped and raw Micrio short-ID extraction.
Port the National Gallery live test.
Port the Memoire des hommes direct-info live test. (Cancelled: the 2026-08-29 audit found a private backend and an unavailable first tile.)
Port the London Museum live test. (Cancelled: the current host returns TLS status 525; retain the deterministic adapter fixture.)
Port the Philadelphia Museum live test.
Port the Liechtenstein Collections live test.
Port the CSNTM direct-info live test.
Port the ONB Presentation manifest live test.
Port the Oklahoma CONTENTdm live test.
Port the University of Washington Mirador live test.
Port the National Library of Israel direct-info live test. (Cancelled: the current endpoint returns HTTP 403.)
Port the NLS Auchinleck direct-info live test.
Port the NLS map-view malformed-metadata live test.
Port the Westchester CONTENTdm live test. (Cancelled: the CONTENTdm API timed out.)
2.5 IIPImage and krpano
Port the IIPImage 512x512 fixture and final JTL=1,3 tile assertion.
Port the krpano explicit-level fixture and final tiles/l1/2_2.jpg assertion.
3. Port missing dezoomers to dezoomify-rs
Each format PR must include parser/geometry unit tests, a deterministic discovery-operation fixture, automatic registry selection, malformed-input coverage, and the listed live test behind DEZOOMIFY_LIVE_TESTS.
3.1 XLimage
Implement direct ?cmd=info metadata parsing and ?cmd=tile&x=&y=&z= known-grid requests as a routed spec.
Implement the KBR page rewrite as a deferred adapter only if section 1 proves it is still live.
Port the deterministic sample.imgi?cmd=info fixture and x=1&y=1&z=1 assertion.
Port the Uffizi live test.
3.2 TopViewer/Memorix
Implement direct TopViewer JSON parsing and linear global tile numbering.
Implement generic Memorix thumbnail discovery.
Implement <pic-mediabank> detail and gallery API chains as stateful discovery.
Add only institution mappings that survive the section 1 audit.
Port the direct JSON fixture.
Port the HTML-vs-IIPImage precedence fixture.
Port the Beeldbank detail and Midden-Groningen gallery fixtures.
Port all eight surviving institution mapping assertions.
Port direct Memorix, Beeldbank Groningen, and Midden-Groningen live tests.
3.3 FSI
Implement direct FSI metadata and rectangle-based image requests.
Implement HTML viewer discovery as stateful/deferred discovery.
Port the deterministic info fixture and normalized image-request assertion.
Port the Neptune Labs live test.
3.4 LizardTech ImageServer
Implement calcrgn XML parsing, pyramid geometry, and getimage center-point requests.
Port the Alabama Maps fixture and exact encoded getimage URL assertion.
Port the Alabama Maps live test.
3.5 Visual Library Server
Implement /zoom/<id> page discovery as a thin adapter that emits the existing generic tile template rather than a second tile engine.
Port the deterministic VLS fixture and generated /image/tiler/square/.../0/0/0 assertion.
Port the BLB VLS live test with its required cookie through the native host.
3.6 Hungaricana
Implement page-to-ECW discovery and image-size metadata parsing.
Implement the protocol's per-tile cryptographic path generation.
Port viewer basemapUrl extraction, query-token preservation, f= removal, and nonzero global-coordinate assertions.
Port the uncached-service rejection fixture.
Add and port the Cartesius/NGI live test.
3.9 pnav
Implement object-page og:image extraction and sidecar dimension metadata.
Implement crop request generation, adaptive probing/scaling, and edge behavior.
Port the deterministic object-page fixture and exact first crop URL.
Port the Pushkin Museum live test.
Port the Ethnographic Museum live test.
3.10 Parity gate
Compare the legacy script registry with the Rust built-in registry and account for every surviving entry.
Run all deterministic legacy and Rust parity fixtures in CI.
Run both live suites and document differences caused by CORS/proxy policy rather than format parsing.
Freeze additions to legacy dezoomers; add new format logic to Rust only after this point.
4. Expose dezoomify-core through WASM
4.1 Freeze the host contract
Define the hosted MVP as one selected image and level, known/positioned/adaptive tile sources, PNG/JPEG output, cancellation, and partial results.
Exclude bulk mode, TIFF/ZIF/IIIF-directory output, persistent cache, arbitrary cookies, and unrestricted request headers from the first browser release.
Define versioned TypeScript messages for start, cancel, catalog, image selection, level selection, progress, warning, result, and structured error.
Use stable string IDs across JS/WASM and worker messages; never expose Rust u64 as an unchecked JavaScript number.
4.2 Add a dedicated adapter crate
Add a dezoomify-wasm workspace crate with cdylib/rlib, wasm-bindgen, and serde-wasm-bindgen.
Keep wasm-bindgen, js-sys, web-sys, fetch, and canvas dependencies out of dezoomify-core and add them to the architecture-test denylist.
Implement opaque known/positioned plan handles with lazy next_batch(max_tiles) DTOs.
Include request URL, headers, destination, expected size, role, and processing recipe in each tile DTO.
Test row-major order, edge clipping, DZI overlap, positioned layouts, generated Referer, repeatability, and counts beyond JavaScript's exact integer range.
4.5 Wrap adaptive plans and processing
Keep ProbeContinuation inside WASM and expose next_probe, submit_available(width,height), and submit_missing.
Return resolved dimensions/count and avoid returning successful probe tiles a second time.
Test exact 3x2 discovery, missing origin, zero dimensions, prior output, padded/case-insensitive templates, and identical probe/resolved URLs.
Export tile processing for Google Arts encrypted bytes and return a structured processing error.
Test processed bytes with the existing encrypted tile fixture and an actual image decode.
Benchmark JS-to-WASM copies and retained discovery bytes near the metadata limit.
Investigate extra response cloning only for stateful Google Arts and krpano operations; do not block routed formats on that optimization.
4.6 Package the WASM core
Pin wasm-pack and generate TypeScript declarations.
Run npm pack and install the tarball in a minimal consumer during CI.
Record raw, gzip, and Brotli package sizes.
Publish a prerelease npm package with the Rust version/commit in its metadata.
Normalize GPL-compatible package metadata before publication.
5. Build the modern hosted web app
5.1 Create a parallel modern build
Add a TypeScript/Vite build with locked dependencies, type checking, linting, unit tests, and hashed assets.
Serve the new app at /beta/ while the current root app remains available.
Load the versioned WASM npm package; do not copy Rust registry or tile logic into the web repository.
Serve WASM with application/wasm and configure immutable caching for hashed JS/WASM plus no-cache HTML.
5.2 Put orchestration in a worker
Create a dedicated module worker that owns WASM handles, fetch scheduling, tile processing, decoding, assembly, retries, and cancellation.
Put a job ID on every command/event so stale events cannot mutate a later run.
Cancel with AbortController, close ImageBitmaps, dispose handles, and recreate the worker after a stuck parser/export.
Add worker initialization, forced-failure recovery, and repeated-disposal tests.
5.3 Implement browser transport and a safe proxy
Define one transport interface for direct and proxied metadata/tile requests.
Try direct fetch first when CORS and required headers allow it; fall back to the proxy only on a network/CORS failure.
Merge headers case-insensitively so user headers override format-generated headers, matching the native app.
Apply metadata byte limits before constructing a complete Uint8Array.
Retry transient fetch, processing, and decode failures; classify adaptive 404/410 or exhausted retries as missing probes.
Add a new POST proxy API while keeping the old /proxy route working for the legacy app.
Allow only HTTP(S), allowlist relayable headers, reject hop-by-hop headers, revalidate redirects, and enforce timeout/redirect/response-size limits.
Block loopback, link-local, private-network, and cloud-metadata targets where the platform can enforce it.
Do not forward arbitrary Cookie or Authorization headers in the hosted default mode.
Return stable status/content-type/final-URL/error fields and add direct-CORS, fallback, redirect, abort, SSRF, oversized-response, and forbidden-header tests.
5.4 Implement discovery and selection UX
Populate automatic/named format choices from WASM registry metadata.
Drive one priority request at a time until a catalog or structured error is returned.
Show a catalog picker for multiple images and resolve only the selected deferred entry.
Enforce deferred-depth and total-entry limits across discovery operations.
Show a level picker with label, dimensions, tile count, and warnings.
Default to the largest known level that fits browser limits rather than blindly selecting the final array item.
Link unsupported formats and oversized jobs to the native application.
5.5 Download and assemble fixed plans
Pull small tile batches lazily from WASM.
Use bounded configurable concurrency, retry count, and optional request interval.
Apply the Rust processing recipe before decoding.
Decode with createImageBitmap, validate nonzero dimensions, draw at the core-provided destination, and close each bitmap immediately.
Continue after terminal ordinary-tile failures and retain a failed-tile count/list for partial output.
Do not recompute overlap, tile order, or edge placement in TypeScript.
5.6 Download and assemble adaptive plans
Fetch and decode one core-requested probe at a time.
Cache successful probe bytes/bitmaps until final dimensions are known.
Report dimensions to WASM and treat a missing probe as search input, not an output failure.
Allocate the final canvas after resolution, draw successful probes exactly once, then fetch remaining tiles.
Change progress from unknown probing to known completed/total download progress.
Release all cached probe resources on success, error, or cancellation.
5.7 Encode browser output safely
Use OffscreenCanvas in the worker where available.
Preflight width, height, width * height * 4, browser canvas limits, and a configurable memory budget.
Reject oversized images with a native-app recommendation; never silently downscale as the legacy app does.
Export PNG and high-quality JPEG blobs.
Preserve a warning and blank/transparent failed regions for partial output.
Create and revoke result object URLs in the main thread.
Report unknown-size positioned layouts as unsupported in the MVP.
5.8 Add structured progress and errors
Emit phases for initializing, discovering, image selection, deferred resolution, level selection, probing, downloading, encoding, complete, and cancelled.
Define stable error codes for invalid input, unknown format, discovery fetch/rejection/limit, empty catalog, unsupported level, canvas limit, tile fetch/decode/processing, proxy, encoding, cancellation, and WASM panic.
Keep user-facing messages separate from diagnostic URLs, status codes, retry counts, and causes.
5.9 Add blocking browser acceptance tests
Generic adaptive 2x2 fixture with output-pixel assertions.
Zoomify metadata input and tile-URL input with query token.
DZI overlap fixture with output-pixel assertions.
IIIF Image API 2 and 3 fixtures.
IIIF Presentation manifest with multiple/deferred entries.
Google Arts encrypted processing fixture.
krpano chained metadata fixture.
IIPImage fixture.
Custom YAML positioned layout and request headers.
Direct CORS success and proxy fallback.
Out-of-order tile completion and edge cropping.
Partial output after a terminal tile failure.
Cancellation during metadata fetch and tile download.
Canvas-limit error without scaling.
PNG/JPEG MIME and nonempty blob.
Worker recovery after forced failure.
Run Playwright against the production dist build, not only the dev server.
5.10 Deploy and retire legacy code
Add preview deployments for pull requests and production deployment only from protected master.
Add a CSP covering scripts, workers, network targets, blob images, and WASM execution.
Keep live compatibility tests non-blocking but visible.
Compare beta and legacy results for every surviving format and live target.
Move the modern app to the root only after deterministic parity, proxy-security, cancellation, and output-pixel suites pass in production-like hosting.
Remove legacy global dezoomers, automatic.js, duplicate tile planning, and canvas assembly after the cutover.
Keep the native Rust app as the supported path for local files, very large images, persistent cache, custom native headers, TIFF/ZIF, and IIIF-directory output.
Done when
Every surviving legacy branch is either represented by a deterministic Rust test or explicitly removed with evidence that its deployment is dead.
Every surviving JavaScript dezoomer has a Rust implementation and fixture/live parity coverage.
The hosted app imports the versioned WASM package and contains no format-specific tile logic.
Native and web products share registry-derived discovery, catalogs, level selection, tile requests, destinations, and processing recipes.
The deployed modern app passes the blocking browser suite without silently reducing output resolution.
Consolidate dezoomify around the Rust core
Goal
Make
dezoomify-corethe single implementation of format discovery and tile planning, use it from the native application and a new browser application through WASM, then remove the duplicate JavaScript dezoomers.The first foundation phase shipped in dezoomify-rs 2.19.0.
dezoomify-coreis pure Rust with no I/O, async runtime, image decoder, or filesystem dependency. It already provides the discovery state machine, catalog and level model, registry, known and adaptive tile plans, and tile-processing recipes.The remaining work is deliberately split into small parity, porting, and product-integration steps below.
Rules for this migration
dezoomify-corehost-neutral. Fetching, CORS/proxy policy, decoding, assembly, persistence, and UI stay outside the core.DezoomerSpecand add it to the canonical Rust registry; use an immediate program or orderedDiscoveryRoutetable according to its resource flow.1. Audit and shrink the legacy JavaScript app
1.1 Remove already-orphaned test data
The PFF, old pre-IIIF Micrio, and Mnesys handlers were removed after no live deployment could be found. Their fixtures remain.
requestType=1andrequestType=2fixtures and the unused fixture-server route.api/getTilesInfofixture. Keep current Micrio-as-IIIF fixtures.p.xmlfixture.mirador.html, the CONTENTdm record HTML, and the Memorix detail HTML/API pair are reached by any test; delete each file that is not reached.issue_81JPEG used as a generic response with a minimal named fixture, then delete the other 62 unreferenced tiles and metadata.1.2 Test every unverified Zoomify branch
Source:
dezoomers/zoomify.js.biblio.unibe.ch/web-apps/maps/zoomify.phpbranch.bspe-p-pub.paris.fr/MDBGED/zoomify-BFS.aspxbranch.artandarchitecture.org.uk/images/zoombranch.zoomifyImagePathpage extraction with a deterministic fixture.showImagepage extraction and<base href>resolution; retain the existing fixture.accessnumbertoXMLBroker.new.phprewrite..ete-openlayers-srcextraction.zoomifytileserviceandtilesUrlextraction.<url>...</url>extraction.ImageProperties.xml, directTileGroupURL, tile-group arithmetic, and full-resolution-onlyNUMTILESfixtures even if all site-specific branches are removed.1.3 Test every unverified Seadragon/DZI branch
Source:
dezoomers/seadragon.js.data-pyrpage; its hosted target returns HTTP 403, so the deterministic Las Meninas fixture remains and the live case is removed.Viewer.aspxtoProxy.ashxrewrite./viewto/dzirewrite and special tile origin, or remove that branch.view/<group>/<index>extraction.zoom.itandzoomhub.netcontent detection..xml,.dzi, anddzi=links independently ofSeadragon.embed.Seadragon.embed, and overlap-placement fixtures regardless of site cleanup.1.4 Test every unverified IIIF/site-adapter branch
Source:
dezoomers/iiif.js.ark:/to IIIF conversion.micrio.vangoghmuseum.nlto CDN rewrite.<micr-io id>custom element; retain the deterministic fixture.viewer.onb.ac.at/<id>form with and without a page number.digital.onb.ac.at/RepViewerform.tile_widthfallback used bymap-view.nls.uk.1.5 Test every unverified TopViewer/Memorix branch
Source:
dezoomers/topviewer.js.gra) and retain its live case.sha) direct detail mapping.zaa) direct detail mapping.szu) direct detail mapping.ranh) direct detail mapping.<pic-mediabank>detail and gallery API discovery; retain the Historisch Archief Midden-Groningen live case.server: "..."JSON branch.1.6 Test remaining site-specific branches
/g.co/arts/short-link entry form.hyper-photo.com/hyperpanohint; retain the krpano live case and protocol fixtures.?cmd=infosupport.imagepath, inlinefiles/images, andfiles_urlpage discovery; retain direct ECW and live gallery cases.catalog.shm.ruis blocked.(0,0).1.7 Run and classify every current live target
Run each case individually so one flaky host does not hide another result. A passing generic protocol target does not validate a separate site-specific branch.
2. Port legacy tests for formats already in dezoomify-rs
Port deterministic behavior first. Keep site adapters separate from core protocol parsers. Tests already covered by the same Rust fixture/live target do not need to be duplicated: Arts & Culture live, generic fixture/live, HNG IIPImage live, and krpano live.
2.1 Cross-format selection
2.2 Zoomify
ImageProperties.xmlfixture and finalTileGroup0/1-1-1.jpgassertion.<base>plusshowImagediscovery as a deferred Zoomify adapter test.NUMTILES=280regression; all 280 full-resolution tiles must remain inTileGroup0, including6-16-6.jpg.Port the OpenSeadragon Zoomify example-page live test.(Cancelled: the current viewer references a deleted ImageProperties.xml path; retain the direct Zoomify live test.)2.3 Deep Zoom/DZI
sample.dzifixture and finalsample_files/9/1_1.jpgassertion..dzidiscovery..jpegtile URL input and assert sibling.dzidiscovery.Seadragon.embed(..., "legacy.xml")discovery as a deferred DZI adapter test.(0,0),(255,0),(0,255),(255,255)as an end-to-end DZI test.data-pyrfixture, including dimensions, tile size, overlap, maximum level, and first tile URL.2.4 IIIF
?manifest=query extraction as a deferred IIIF adapter test.#?manifest=fragment extraction as a deferred IIIF adapter test.<micr-io id>extraction as a deferred IIIF adapter test.info.jsonbase.:80origin.info.jsondiscovery.Port the Memoire des hommes direct-info live test.(Cancelled: the 2026-08-29 audit found a private backend and an unavailable first tile.)Port the London Museum live test.(Cancelled: the current host returns TLS status 525; retain the deterministic adapter fixture.)Port the National Library of Israel direct-info live test.(Cancelled: the current endpoint returns HTTP 403.)Port the Westchester CONTENTdm live test.(Cancelled: the CONTENTdm API timed out.)2.5 IIPImage and krpano
JTL=1,3tile assertion.tiles/l1/2_2.jpgassertion.3. Port missing dezoomers to dezoomify-rs
Each format PR must include parser/geometry unit tests, a deterministic discovery-operation fixture, automatic registry selection, malformed-input coverage, and the listed live test behind
DEZOOMIFY_LIVE_TESTS.3.1 XLimage
?cmd=infometadata parsing and?cmd=tile&x=&y=&z=known-grid requests as a routed spec.sample.imgi?cmd=infofixture andx=1&y=1&z=1assertion.3.2 TopViewer/Memorix
<pic-mediabank>detail and gallery API chains as stateful discovery.3.3 FSI
3.4 LizardTech ImageServer
calcrgnXML parsing, pyramid geometry, andgetimagecenter-point requests.getimageURL assertion.3.5 Visual Library Server
/zoom/<id>page discovery as a thin adapter that emits the existing generic tile template rather than a second tile engine./image/tiler/square/.../0/0/0assertion.3.6 Hungaricana
3.7 WMTS
/0/10/10.jpgassertion.3.8 ArcGIS cached MapServer
MapServer?f=jsonmetadata routing and preserve non-fquery parameters./tile/<level>/<row>/<column>requests.basemapUrlextraction, query-token preservation,f=removal, and nonzero global-coordinate assertions.3.9 pnav
og:imageextraction and sidecar dimension metadata.3.10 Parity gate
4. Expose dezoomify-core through WASM
4.1 Freeze the host contract
u64as an unchecked JavaScript number.4.2 Add a dedicated adapter crate
dezoomify-wasmworkspace crate withcdylib/rlib,wasm-bindgen, andserde-wasm-bindgen.wasm-bindgen,js-sys,web-sys, fetch, and canvas dependencies out ofdezoomify-coreand add them to the architecture-test denylist.cargo check -p dezoomify-core --target wasm32-unknown-unknown.cargo check -p dezoomify-wasm --target wasm32-unknown-unknown.wasm-bindgen-testCI and a compressed WASM size budget.4.3 Wrap discovery as opaque handles
DiscoveryHandle::new(input, dezoomer, limits)aroundDiscoveryOperation.next_request()returning exactly one of request, complete, or structured error.supply_bytes(request_id, Uint8Array)andsupply_failure(request_id, failure).4.4 Wrap catalogs and plans
CatalogHandlesummaries for ready/deferred entries, titles, warnings, formats, and levels.next_batch(max_tiles)DTOs.4.5 Wrap adaptive plans and processing
ProbeContinuationinside WASM and exposenext_probe,submit_available(width,height), andsubmit_missing.4.6 Package the WASM core
wasm-packand generate TypeScript declarations.npm packand install the tarball in a minimal consumer during CI.5. Build the modern hosted web app
5.1 Create a parallel modern build
/beta/while the current root app remains available.application/wasmand configure immutable caching for hashed JS/WASM plus no-cache HTML.5.2 Put orchestration in a worker
AbortController, closeImageBitmaps, dispose handles, and recreate the worker after a stuck parser/export.5.3 Implement browser transport and a safe proxy
Uint8Array./proxyroute working for the legacy app.5.4 Implement discovery and selection UX
5.5 Download and assemble fixed plans
createImageBitmap, validate nonzero dimensions, draw at the core-provided destination, and close each bitmap immediately.5.6 Download and assemble adaptive plans
5.7 Encode browser output safely
OffscreenCanvasin the worker where available.width * height * 4, browser canvas limits, and a configurable memory budget.5.8 Add structured progress and errors
5.9 Add blocking browser acceptance tests
distbuild, not only the dev server.5.10 Deploy and retire legacy code
master.automatic.js, duplicate tile planning, and canvas assembly after the cutover.Done when