Skip to main content

Compressed slide tiles in Python

This optional Rust extension exposes wsi_rs.Slide, slide metadata, tile geometry, and compressed tile bytes. It does not expose pixel decoding; use the separate j2k extension for JPEG/JPEG 2000 tensors.

python -m pip install wsi-rs

Releases publish wheels to PyPI for Python 3.10 and later on Linux x86_64 and aarch64 (glibc 2.28 or newer), macOS arm64 and x86_64, and Windows x64, and attach them to the GitHub release. To build from a checkout instead:

uvx maturin build --manifest-path wsi-rs-python/Cargo.toml --release --out target/python-wheels
python -m pip install --no-deps --no-index --find-links target/python-wheels wsi-rs
python -m unittest discover -s wsi-rs-python/tests -v
import wsi_rs
import j2k

slide = wsi_rs.Slide.open("case.svs")
print(slide.properties)
print(slide.levels())
hits = slide.tiles_for_region((512, 768, 256, 256), level=0)
tiles = slide.read_tiles_compressed([hit.coords for hit in hits], level=0)
requests = [j2k.ImageRequest(tile.data, color_transform=tile.color_transform) for tile in tiles]
batch = j2k.Decoder(device="cpu").decode_batch(requests)

Slide(path) and Slide.open(path) accept strings and path-like objects. metadata describes scenes, series, (z,c,t) axes, channels, levels, associated-image dimensions, and properties. levels(scene=0, series=0) returns independent dictionaries with dimensions, downsample, and tile-grid metadata. Regular and virtual grids report tile size and grid size. Irregular grids report advance, extra tiles, and tile count.

tiles_for_region((x,y,width,height), level=0, scene=0, series=0) uses pixels at the selected level. Each hit supplies (column,row) as coords and the tile's placement relative to the requested origin as offset. Placement may be fractional for irregular layouts. The reader's order is preserved. This plans coverage only; patch cropping, overlap handling, and assembly remain with the application.

read_tiles_compressed(coords, level=0, scene=0, series=0, plane=(0,0,0)) returns immutable CompressedTile objects in caller order, including duplicate coordinates. Each has data (owned Python bytes), coords, width, height, codec, bits_allocated, significant_bits (the low bits of each sample that carry it, or None when all do), samples_per_pixel, photometric_interpretation, color_transform, and tile_region. JPEG hints are auto, ycbcr, or none; non-JPEG inputs use auto. JPEG tables are spliced and supported NDPI tiles are re-tiled by the existing Rust reader. Unsupported raw-tile routes raise an error. The binding never substitutes decoded RGBA or a black tile.

Coordinate sequence length is checked against the metadata budget before copying it into Rust. Invalid coordinate items are reported by input index.

tile_region is (x,y,width,height) of the requested tile inside the encoded image. It is smaller than the image when the stored image is larger than the tile: an edge tile in a padded TIFF tile or DICOM frame, a tile cut losslessly from a larger JPEG whose block (MCU) grid does not start at the tile origin (the encoded image then starts at the previous block boundary), or a tile inside a whole JPEG 2000 or JPEG XR image that is returned unchanged. A tile whose lossless JPEG crop would exceed the reader's crop limit (256 MiB of working memory by default) also comes back as the whole stored JPEG, unchanged and standalone, with tile_region locating the tile; jpegtran -crop or a decode followed by slicing extracts it.

A tile read failure raises an exception naming the failing input; a failed batch never returns a partial list. Reader resource limits still apply. Encoded results are additionally capped at the default 256 MiB batch-chunk limit; request fewer tiles when needed. Tile planning observes the reader's region and metadata limits. Payloads stay valid after the slide object is destroyed.

Open, compressed reads, location queries and assemble release the GIL. Open one Slide per DataLoader worker and prefer multiprocessing spawn; inherited handles are rejected after fork. There is no NumPy or PyTorch dependency in this reader wheel. The Python API is experimental; no wheel publication is part of this change.

When a local j2k wheel and NumPy are installed, the tests also exercise TIFF color hints and table splicing through the tensor decoder. With a Metal build and PyTorch MPS, they decode a DICOM JPEG 2000 tile directly into an MPS tensor. Set WSI_REQUIRE_J2K=1 to require the optional codec integration tests.

Tile byte locations

tile_location(col, row, level=0, scene=0, series=0, plane=(0,0,0)) reports where a tile's encoded bytes are stored, from the file's index, without decoding the tile (a few formats read a handful of marker bytes). level_tile_locations(level=0, scene=0, series=0, plane=(0,0,0)) does the same for a whole level in one call and returns tile_width, tile_height, tiles_across, tiles_down, and tiles, a tuple of (col, row, location) in row-major order. It is bounded by the reader's tile-index limit; one unreadable location fails the whole call and names the tile. Formats without location support raise ValueError.

A TileLocation has a kind:

  • stored: tile_size is the tile clipped at the level edge, and units lists the stored encoded images it is made from. Most formats use one unit per tile; a tile of a strip-based TIFF lists every strip it covers.
  • absent: the file stores no pixels for the tile (a sparse or empty TIFF tile, a missing DICOM frame, VSI background). Readers paint background; Zarr leaves the chunk out and uses fill_value.
  • not_addressable: no byte range holds the tile's pixels. reason is synthetic_level (with base_level and factor), resampled, codestream_window (a window of one large JPEG 2000 codestream), or not_stored.

An EncodedUnit has path (the slide file as the reader opened it), segments ((offset, length) byte ranges in stream order), framing, prefix and suffix bytes, codec, stored_size (including edge padding), source_region (the part of the stored image the tile uses) and tile_region (where that part lands in the tile). codec is a dictionary with compression (the same names as CompressedTile.codec), bits_per_sample, significant_bits (the low bits of each sample that carry it, or None when all do), samples_per_pixel, photometric_interpretation, planar_configuration (chunky or planar), channel_order (rgb, or bgr for CZI's B, G, R samples), predictor (none, horizontal or floating_point), byte_order (little, big or None), chroma_subsampling and jpeg_tables (bytes or None).

framing The bytes at segments are
standalone A complete stream: a JPEG with its tables, a JPEG 2000 codestream, a JPEG XR image.
jpeg_tables A TIFF abbreviated JPEG from its SOI marker. Its tables are codec["jpeg_tables"]; pass them as tables= to imagecodecs.jpeg8_decode or to the imagecodecs_jpeg numcodecs codec.
bare_payload A codec payload without framing, such as TIFF LZW, Deflate, Zstandard or uncompressed data. Decode it with codec, including its predictor and byte order.
prefixed Part of a larger JPEG (NDPI). The standalone stream is prefix, the segments, then suffix. With the usual suffix b"\xff\xd9", the imagecodecs_jpeg codec's header=prefix rebuilds it.

unit.assemble(parts) takes the bytes of each segment, read in order, and returns the standalone stream. For a unit that covers its whole tile, that is the same data read_tiles_compressed returns, with one exception: a CompressedTile cannot carry a predictor, separate sample planes, a non-native byte order, B, G, R sample order or masked high bits, so such bare payloads are read as exact none samples instead. Subsampled (packed) YCbCr payloads have locations but no raw read. to_dict() on a level, a location or a unit returns plain ints, strings, bytes, lists and dictionaries; only the bytes need encoding before json.dumps. Values a newer reader adds are reported as unknown.

A kerchunk-style reference needs one byte range per chunk. This sketch uses only the standard library and accepts 8-bit JPEG levels in which every stored tile is one byte range holding one full-size encoded tile:

import base64
import json
import wsi_rs

slide = wsi_rs.Slide.open("case.svs")
width, height = slide.levels()[0]["dimensions"]
locations = slide.level_tile_locations(level=0)
tile = (locations.tile_width, locations.tile_height)
refs, codec = {}, None
for col, row, location in locations.tiles:
    if location.kind == "absent":
        continue  # zarr fills missing chunks with fill_value
    unit = location.units[0] if location.kind == "stored" and len(location.units) == 1 else None
    if (unit is None or len(unit.segments) != 1 or unit.framing not in ("standalone", "jpeg_tables")
            or unit.stored_size != tile or unit.source_region != (0, 0, *location.tile_size)
            or unit.tile_region != unit.source_region):
        raise ValueError(f"tile {col},{row} is not one stored chunk: {location.to_dict()}")
    if codec not in (None, unit.codec):
        raise ValueError("tiles of this level use different codecs")
    codec = unit.codec
    offset, length = unit.segments[0]
    refs[f"0/{row}.{col}.0"] = [unit.path, offset, length]
if codec is None or codec["compression"] != "jpeg" or codec["bits_per_sample"] != 8:
    raise ValueError("this sketch handles 8-bit JPEG levels only")
compressor = {"id": "imagecodecs_jpeg"}
if codec["jpeg_tables"] is not None:
    compressor["tables"] = base64.b64encode(codec["jpeg_tables"]).decode()
if codec["photometric_interpretation"] == "rgb":
    compressor["colorspace_jpeg"] = "RGB"  # RGB components, no YCbCr transform
samples = codec["samples_per_pixel"]
refs[".zgroup"] = json.dumps({"zarr_format": 2})
refs["0/.zarray"] = json.dumps({
    "zarr_format": 2, "shape": [height, width, samples], "chunks": [tile[1], tile[0], samples],
    "dtype": "|u1", "compressor": compressor, "fill_value": 0, "order": "C", "filters": None,
})
reference = {"version": 1, "refs": refs}

Edge tiles of tiled TIFFs are stored padded to the full tile size, so they map to full chunks. Units cut from a larger image, multi-segment units and tiles built from several units need read_tiles_compressed or a reader that can crop or join them.

Metadata

Release files for wsi-rs 0.9.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wsi-rs 0.9.2
File Size Uploaded Provenance Actions
wsi_rs-0.9.2.tar.gz 1.6 MB With provenance Details for wsi_rs-0.9.2.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for wsi-rs 0.9.2
File Actions
wsi_rs-0.9.2-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details for wsi_rs-0.9.2-cp310-abi3-win_amd64.whl
wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details for wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl
wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details for wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_aarch64.whl
wsi_rs-0.9.2-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for wsi_rs-0.9.2-cp310-abi3-macosx_11_0_arm64.whl
wsi_rs-0.9.2-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for wsi_rs-0.9.2-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 24.1 MB

Release files / wsi_rs-0.9.2.tar.gz

Download URL wsi_rs-0.9.2.tar.gz
Size 1.6 MB
Tags Source
SHA-256 checksum
How to use checksums
25dea8276b7956ade1e356d6885c673eb75f53569f6cc9b9c9ec438758a66209
BLAKE2b-256 checksum
How to use checksums
ff5687c9ec80e28cb1a42f4608437c63f2d175db5e800a4b9743b70e0fe69d7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / wsi_rs-0.9.2-cp310-abi3-win_amd64.whl

Download URL wsi_rs-0.9.2-cp310-abi3-win_amd64.whl
Size 4.3 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
dfdcdd3420d1ff78c12a4752c6f63c888c493f6b42f13111ad6cac9cd37b7c40
BLAKE2b-256 checksum
How to use checksums
c183fe690a315d502dc4a64e43ee1fbd152d12f76bb0895c75379b27e56edb0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl
Size 4.9 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
d429f96fe1e0789529898af5eaf14c99da3c41cb57a40163dc80878fdb4e4b3a
BLAKE2b-256 checksum
How to use checksums
d769388ff36541f6338d350b5008131a5c3cea8f217a0da4545d24fecd06c2b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL wsi_rs-0.9.2-cp310-abi3-manylinux_2_28_aarch64.whl
Size 4.5 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
2cee1c1814406798db1a3e6741747cb7036d242a192059691b905aa2258a5be7
BLAKE2b-256 checksum
How to use checksums
afbe093fd41d05bd57445dc7f1c990cfeb1e135a2c2ed76858b05bcb8ad112c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / wsi_rs-0.9.2-cp310-abi3-macosx_11_0_arm64.whl

Download URL wsi_rs-0.9.2-cp310-abi3-macosx_11_0_arm64.whl
Size 4.1 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
ec7be20382a0fc13f93cbd535dd4e8c59d77676dc7ea12eb28c1b73037c26fe9
BLAKE2b-256 checksum
How to use checksums
eadd535bfe6397a33990f9877da42b975582634aac23bcd4ddb81d84aaadd5ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / wsi_rs-0.9.2-cp310-abi3-macosx_10_12_x86_64.whl

Download URL wsi_rs-0.9.2-cp310-abi3-macosx_10_12_x86_64.whl
Size 4.6 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
50059d7b671715a13fc94321760d2abde0a909d97fc6721964844aa615dd050c
BLAKE2b-256 checksum
How to use checksums
6945cfc646afa8b3610a2b9d1b1128fc181960200ee2abea44cb1f65e38580c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Security for wsi-rs 0.9.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 6 files in this release have been uploaded with provenance metadata.

Select from 6 files

Attestation for wsi_rs-0.9.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page