Skip to content

Repository files navigation

wsi-rs

CI crates.io docs.rs License: MIT OR Apache-2.0

wsi-rs is a Rust whole-slide image reader. It opens TIFF-family WSI, including ARGOS and Huron, DICOM VL WSI, Zeiss CZI/ZVI, MIRAX, Hamamatsu VMS/VMU, Olympus VSI/ETS, raw JPEG 2000 codestream fixtures, and .svcache containers. JPEG, JPEG 2000, and HTJ2K decode is delegated to the J2K pure-Rust JPEG 2000 codec crates. JPEG XR decoding uses the separate JXR codec.

The main crate denies unsafe code by default, with a narrowly scoped, audited exception for Metal interoperability. Unsupported or incomplete sources return WsiError; they should not silently produce black or partial pixels.

Install

cargo add wsi-rs

Supported architectures are x86_64 and aarch64. The JPEG backend in the required j2k 0.10 series does not support 32-bit targets.

Quick Start

use wsi_rs::{RegionRequest, Slide, TileRequest};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let slide = Slide::open("sample.svs")?;

    let region = RegionRequest::builder(0usize, 0usize, 0u32)
        .origin_px((0, 0))
        .size_px((1024, 1024))
        .build()?;
    slide.read_region_rgba(&region)?.save("region.png")?;

    let tile = TileRequest::builder(0usize, 0usize, 0u32).tile(0, 0).build()?;
    let cpu_tile = slide.read_tile(&tile)?;
    println!("{}x{}", cpu_tile.width(), cpu_tile.height());

    Ok(())
}

Use SlideOpenOptions for explicit cache budgets, read-through .svcache lookup, custom registries, region limits, or decode execution settings.

Every slide also has checked hostile-input limits. The defaults are 128 MiB aggregate metadata, 16 MiB per metadata value, 128 MiB each for tile indexes, encoded units, and decoded outputs, 33,554,432 pixels/128 MiB RGBA per region, 384 MiB transient work per operation, 512 MiB in flight per slide, and a 256 MiB internal batch-chunk target. Oversized batches are processed in order; only an individually oversized tile, associated image, or region is rejected. Use SlideLimits through SlideOpenOptions::with_limits to choose stricter checked limits.

Architecture

wsi-rs presents a format-independent Slide façade backed by a SlideReader. Format modules own metadata validation, tile or frame lookup, and source I/O; the shared core owns typed requests, byte-bounded caches, decode policy, and CPU output types. Unsupported or invalid input returns a typed WsiError instead of silently producing a partial tile. The detailed internal ownership map is in docs/architecture.md.

Batch reads preserve request order and cardinality. The default controlled-read adapter checks cancellation, submits the complete request slice once, validates the result count with WsiError::BackendContract, and checks cancellation again before returning. Format-specific implementations may group internal I/O, but they restore results to the original request slots. Cancellation is terminal for that attempt and is not reinterpreted as a codec error or a reason to fall back from device output to CPU. JPEG and JPEG 2000 kernels already running remain non-preemptive.

Encapsulated DICOM images lazily share one validated frame index between reads and prepare_level_controlled. The normal indexer seeks over compressed payloads, prefers a valid Extended Offset Table, and otherwise validates the Basic Offset Table and Item headers. Unusual supported layouts retain a token parser fallback. Index construction checks counts, monotonic offsets, arithmetic, file bounds, frame lengths, and NumberOfFrames; it publishes only complete indexes and creates no sidecar files.

SlideOpenOptions owns cache configuration. The shared source-tile and display composition caches are byte-bounded LRUs, while narrowly scoped format caches cover source-specific data such as DICOM frame bytes. Those private caches share one aggregate allocation derived from the configured source-tile budget; excess per-image or per-shard caches remain disabled instead of preallocating outside that policy. Cache effects completed by a legacy reader are not rolled back when a controlled read is cancelled, but a cancelled result is not returned to the caller. .svcache freshness policies stream the complete source through SHA-256, so opting into cache resolution performs a full source-file read; implicit .svcache resolution remains disabled by default.

Default retained caches are capped at 128 MiB per slide: 64 MiB for decoded source tiles, 32 MiB for display tiles, and 32 MiB across private and full-decode caches. Explicit cache settings may choose a different budget.

Metal and CUDA features accelerate JP2K/HTJ2K CPU reads automatically when a measured device route, including readback, wins by at least 15%. The ordinary API always returns CpuTile and falls back safely. Expert read_tile(s)_metal and read_tile(s)_cuda methods are strict: they support only JP2K/HTJ2K and either return typed resident tiles or an error. Both tile types provide checked, pitch-aware download_cpu() staging.

Controlled-read diagnostics are opt-in and delivered outside internal locks. The library emits operational events through tracing, but installs no subscriber and owns no application UI or JSONL output.

For viewer zoom/pan debugging on tiled SVS inputs:

RUST_LOG=wsi_rs=debug WSI_RS_TILE_CACHE_BYTES=134217728 \
  WSI_RS_DISPLAY_TILE_CACHE_BYTES=67108864 your-viewer

WSI_RS_TILE_CACHE_BYTES controls the shared decoded source-tile cache and WSI_RS_DISPLAY_TILE_CACHE_BYTES controls display-tile composition cache capacity. The debug logs include cache hit/miss summaries for region/display tiles and timing for TIFF/SVS JPEG tile batches when the host application installs a tracing subscriber.

Build cache files with:

cargo run --release --bin svcache -- build sample.svs --out sample.svs.svcache

Supported Inputs

Input family Typical paths
TIFF-family WSI (including ARGOS and Huron) and uncompressed RGB TIFF .svs, .tif, .tiff, .ndpi, .scn, .bif, .avs
DICOM VL WSI .dcm files or a DICOM series directory
Zeiss CZI (single-plane brightfield) and ZVI .czi, .zvi
MIRAX .mrxs plus sibling data files
Hamamatsu VMS/VMU .vms, .vmu plus sibling JPEG (VMS) or NGR (VMU) files
Olympus VSI .vsi plus matching ETS companion data
Raw JPEG 2000 codestream .j2k, .j2c
.svcache .svcache

CZI supports single-plane Bgr24 whole-slide images with uncompressed, JPEG, or JPEG XR subblocks. Scenes share a canvas and expose common native pyramid resolutions. JPEG XR Bgr48 preview attachments retain 16-bit samples. Other CZI pixel types, multi-plane datasets, and unsupported compression return errors. Sakura remains excluded until a redistributable real sample is available.

JPEG XR TIFF support covers tiled, contiguous unsigned 8-bit grayscale/RGB images with top-left orientation, no predictor, and no alpha. Physical edge tiles are decoded before cropping. Compressed generic TIFF strips are not newly supported.

Generic strip-based TIFF support is intentionally limited to one top-level, uncompressed 8-bit RGB image with top-left orientation, no predictor, and either interleaved or separate sample planes. Other ordinary TIFF variants remain unsupported unless they use a registered WSI layout.

Hamamatsu VMU pixels

VMU reads the base and map NGR images at focal plane zero, plus an optional JPEG macro image. NGR pixels retain all stored RGB samples as interleaved Uint16 (12 significant bits); native reads do not discard the low four bits. Use read_region_rgba_windowed with DisplayWindow::new(0.0, 4095.0)? for an explicit display conversion. The OpenSlide C shim applies OpenSlide's separate display rule, truncating each sample with sample >> 4 before fractional region composition.

VMU validation currently uses generated fixtures based on OpenSlide's NGR layout, with native sample assertions and independent OpenSlide comparisons. A real scanner-generated VMU fixture has not yet been validated.

Features

Feature Default Description
metal off Metal-backed device payloads on macOS.
cuda off CUDA-backed payload surface.
parity-openslide off OpenSlide oracle parity tests.
parity-metal off CPU-vs-Metal pixel parity checks on macOS.

OpenSlide Compatibility Shim

The workspace includes wsi-rs-openslide-shim, a C ABI library that exports OpenSlide-compatible symbols and routes reads through wsi-rs.

cargo build -p wsi-rs-openslide-shim --release
cargo run -p wsi-rs-openslide-shim --bin wsi-rs-openslide-install -- \
  install --shim target/release/libwsi_rs_openslide_shim.dylib \
  --prefix /tmp/wsi-rs-openslide

Use .so instead of .dylib on Linux. Test in a private prefix before replacing any system OpenSlide library.

Development

cargo xtask validate
cargo xtask rc-preflight
cargo xtask fuzz-check

cargo xtask validate runs the default local gate. cargo xtask rc-preflight runs API and supply-chain checks, fuzz builds and five-minute campaigns for each target, feature-combination checks, validation, release and corpus tests, coverage, performance acceptance, and package dry-run checks. The four-platform RC workflow also verifies the C artifacts.

Performance acceptance requires reviewed capture JSON files in WSI_RS_RC_OPENSLIDE_CAPTURE, WSI_RS_RC_PREVIOUS_CAPTURE, and WSI_RS_RC_CURRENT_CAPTURE. Collect the OpenSlide/current pair with cargo xtask perf-capture-pair <label> using the default five alternating repetitions and worker matrix; collect the previous-release capture with the same corpus, workloads, cache budget, and thread limits. Missing captures or failed comparisons block preflight. Temporary dependency exceptions and their expiry dates are recorded in SUPPLY_CHAIN.md. Releases that include the cuda feature also require the fail-closed CUDA validation workflow on the self-hosted CUDA runner.

Security

Report vulnerabilities privately through GitHub private vulnerability reporting or the repository owner profile.

License

Dual-licensed under either MIT or Apache-2.0, at your option.

About

Rust whole-slide image (WSI) reader for digital pathology: open SVS, NDPI, DICOM VL WSI, CZI, MIRAX, VSI, and TIFF slides with tile/region access and JPEG/JPEG 2000/HTJ2K decode.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages