opentile

package module
v0.60.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

README

opentile-go

⚠️ Status: pre-1.0, under rapid active development. The public API is not yet stable and may change between releases — pin a version and check the CHANGELOG before upgrading.

Go Reference CI Go Report Card Release

opentile-go reads whole-slide pathology images in Go — extracting raw compressed tiles and decoding pixel regions from 12 WSI formats, with pure-Go raw-tile reads and a single cgo dependency for codec decode.

It began as a Go port of the Python opentile library — staying byte-identical on the four formats opentile covers (SVS, NDPI, Philips, OME-TIFF) — and is now a superset: it adds openslide-style decoded-region reading and seven more formats than upstream.

What it does:

  • Raw tile extractionlevel.Tile(x, y) returns the compressed bitstream exactly as stored on disk. Pure Go, no cgo — the zero-copy fast path for tile servers and transcoders.
  • Decoded pixelsReadRegion (arbitrary regions), DecodedTile (single tiles), StitchedTile (clean display tiles for rendering, with caller-chosen size), ReadRegionScaled (downsampled output), RenderThumbnail (whole-slide thumbnail/overview), and RenderMacro (synthesized macro at true physical scale) return *decoder.Image, via cgo codec decoders (JPEG, JPEG 2000, HTJ2K, WebP, AVIF, JPEG XL).
  • Scaled strips / DZIScaledStrips, a libvips-style whole-slide region iterator with byte-bounded peak memory, for Deep Zoom / tile-pyramid generation.
  • 12 formats, auto-detected — Aperio SVS, Hamamatsu NDPI, Philips TIFF, OME-TIFF, Ventana BIF, Leica SCN, generic tiled TIFF, COG-WSI, Iris IFE, SZI, multi-file DICOM WSI, and bare DZI.
  • Associated images & metadata — label / overview / thumbnail / macro, MPP, magnification, vendor properties, and raw per-level / per-image TIFF-tag access.
  • Built for throughput — mmap-backed reads, pool-friendly zero-alloc TileInto, concurrent-safe hot path; decoded-region throughput 3–14× openslide on the in-repo benchmark (Performance).
import (
    opentile "github.com/wsilabs/opentile-go"
    _ "github.com/wsilabs/opentile-go/formats/all"
)

t, err := opentile.OpenFile("slide.svs")
if err != nil { /* ... */ }
defer t.Close()

base, _ := t.Level(0)
tile, err := base.Tile(0, 0) // raw compressed JPEG / JP2K / etc. bytes

Tile(x, y) returns the raw compressed bitstream exactly as stored on disk — pure Go, no cgo, zero-copy. Hand it to any JPEG / JPEG 2000 / etc. decoder downstream, or let opentile-go decode for you — see decoded pixel regions below.

Decoded pixels (shipped). For decoded regions instead of raw bytes — level.ReadRegion, level.DecodedTile, pyr.ReadRegionScaled, pyr.ScaledStrips, all returning *decoder.Image — also register the codec decoders, the same side-effect-import pattern as formats/all:

import (
    opentile "github.com/wsilabs/opentile-go"
    _ "github.com/wsilabs/opentile-go/formats/all" // register format readers
    _ "github.com/wsilabs/opentile-go/decoder/all" // register codec decoders (enables decode)
)

See Reading pixel regions and scaled strips for the API, and decoder/ / resample/ for the codec and resampling layers.

Supported formats

Format Extension Levels Associated Compression Parity bar Detail
Aperio SVS .svs tiled label, overview, thumbnail JPEG, JP2K (passthrough) byte-parity vs. Python opentile docs/formats/svs.md
Hamamatsu NDPI .ndpi tiled (stripped + OneFrame) overview, synthesised label*, Map* JPEG byte-parity vs. Python opentile docs/formats/ndpi.md
Philips TIFF .tiff tiled, with sparse-tile fill label, overview, thumbnail JPEG byte-parity vs. Python opentile docs/formats/philipstiff.md
OME-TIFF .ome.tiff tiled (SubIFD) + OneFrame overview, label, thumbnail JPEG (uint8 RGB only) byte-parity vs. Python opentile + tifffile docs/formats/ometiff.md
Ventana BIF .bif tiled, row-major (<Frame>-declared) storage, with overlap metadata* + ScanWhitePoint blank-tile fill overview, synthesised label*, probability*, thumbnail JPEG tifffile (DP 200) + sampled-tile SHAs (both fixtures) docs/formats/bif.md
Iris IFE* .iris tiled (256×256, native-first inversion) with sparse-tile sentinel label, overview, thumbnail, macro, map, probability + free-form titles + ICC profile + free-form attribute map JPEG, AVIF (passthrough), Iris-proprietary (passthrough) sampled-tile SHAs + synthetic-writer + per-fixture geometry pin docs/formats/ife.md
Generic TIFF* .tiff, .tif tiled pyramidal (≥1 level, geometric scale chain) classifier-assigned: label, overview, thumbnail, or "associated" fallback JPEG, JP2K, LZW, Deflate, None, WebP, JPEG XL, AVIF, HTJ2K (all passthrough) sampled-tile SHAs + per-fixture geometry pin + cross-backing parity docs/formats/generictiff.md
Leica SCN* .scn tiled BigTIFF; multi-region "discontinuous scanning"; multi-channel fluorescence classifier-assigned: overview per auxiliary <image> JPEG sampled-tile SHAs + per-fixture geometry pin + bio-formats CLI parity oracle docs/formats/leicascn.md
Smart Zoom Image (SZI)* .szi ZIP-wrapped Microsoft Deep Zoom pyramid; per-level dim halving; sparse images not supported per spec label, overview (from macro.jpg), thumbnail JPEG / PNG (all passthrough) sampled-tile SHAs + per-fixture geometry pin docs/formats/szi.md
DZI (bare Deep Zoom Image)* .dzi (or directory) filesystem Deep Zoom pyramid; Overlap=0 only; OpenFile only — the .dzi manifest or a directory containing exactly one none JPEG / PNG (all passthrough) sampled-tile SHAs + per-fixture geometry pin docs/formats/dzi.md
COG-WSI* .tiff strict GDAL Cloud Optimized GeoTIFF + WSI private tags (65080-87) + COG_WSI_VERSION ghost-area marker label, overview (from macro or overview WSIImageType), thumbnail source-format preserving (JPEG, JP2K, LZW, …) per-fixture geometry pin + cross-fixture parity vs source format + ErrNotConformantCOGWSI spec validation docs/formats/cogwsi.md
DICOM WSI* .dcm (or directory) multi-file directory series (TILED_FULL + TILED_SPARSE); first multi-file format; OpenFile only — accepts a directory or any one .dcm label, overview, thumbnail (from ImageType LABEL/OVERVIEW/THUMBNAIL) JPEG Baseline + uncompressed (pure-Go WSILabs/dicom parser; no new cgo) sampled-tile SHAs + per-fixture geometry pin; verified on Leica GT450 / 3DHISTECH / Grundium docs/formats/dicom.md

* Marks Go-side extensions beyond upstream Python opentile; see Deviations below.

Detection is automatic. opentile.OpenFile walks the registered factories — first asking each for SupportsRaw(r, size) against the raw byte stream, then falling through to TIFF-parsed Supports(file) — and dispatches the first match. The two-stage dispatch lets non-TIFF formats (IFE) short-circuit before tiff.Open. The generic-TIFF reader registers LAST so vendor format detectors get first crack at any TIFF; it activates as a catch-all only when no vendor factory claims the file. Format packages register at import time via _ "github.com/wsilabs/opentile-go/formats/all".

Format coverage: opentile-go ports the four TIFF formats Python opentile 0.20.0 supports for tile extraction. 3DHistech TIFF (the fifth upstream format) is parked at #2. Ventana BIF — the first beyond upstream's coverage — landed in v0.7. Iris IFE — the first non-TIFF format — landed in v0.8. Generic TIFF — a catch-all reader for tiled pyramidal TIFFs without vendor metadata — landed in v0.10. Leica SCN — the legacy SCN400/SCN400F format, including the first multi-channel fluorescence support — landed in v0.11. Smart Zoom Image (SZI) — a ZIP-wrapped Microsoft Deep Zoom pyramid backed by a shared internal/dzi/ core — landed in v0.16. DICOM WSI — the first multi-file format, reading VL Whole Slide Microscopy Image series via OpenFile on a directory or any .dcm — landed in v0.32. Bare DZI — the filesystem sibling of SZI, reading a .dzi manifest + _files/ tile tree via OpenFile, reusing internal/dzi — landed in v0.52. Sakura SVSlide is parked at #3.

Prerequisites

  • Go 1.23+ (uses iter.Seq2).
  • libjpeg-turbo 2.1+ — JPEG decode + tile-domain ops (NDPI edge-tile fill, Philips sparse-tile fill, OME OneFrame). macOS: brew install jpeg-turbo; Debian / Ubuntu: apt-get install libturbojpeg0-dev.
  • Optional codec libraries, each disableable with a no<codec> build tag if you don't have it: OpenJPEG / JPEG 2000 (nojp2k), libjxl (nojxl), libwebp (nowebp), libavif (noavif), openjph / HTJ2K (nohtj2k). libjpeg-turbo is the only codec linked under every cgo build.
  • pkg-config to resolve the above at build time.

opentile-go uses cgo for codec decodeinternal/jpegturbo/ wraps libjpeg-turbo (incl. its tjTransform lossless DCT-domain crops); the decoder/* packages link the other codec libraries above. Raw-tile reads (level.Tile) are pure Go and need no cgo. Building without cgo (-tags nocgo or CGO_ENABLED=0) is supported: raw-tile reads and SVS / NDPI-stripped passthrough work; decode paths (NDPI OneFrame / edge-tile fill, Philips sparse-tile fill, OME OneFrame, and any non-JPEG codec) return ErrCGORequired.

Install

go get github.com/wsilabs/opentile-go

Pin to v0.5.1 or later (v0.5.0 shipped with a wrong module path; see CHANGELOG).

API

Opening a slide
t, err := opentile.OpenFile("slide.tiff")
if err != nil { /* ErrUnsupportedFormat or open error */ }
defer t.Close()

fmt.Println("format:", t.Format())                 // "svs", "ndpi", "philips-tiff", "ome-tiff", "bif", "ife", "generic-tiff", "leica-scn", "szi", "cog-wsi", "dicom", "dzi"
fmt.Println("levels:", len(t.Levels()))

Pass options to override defaults:

t, err := opentile.OpenFile("slide.ndpi",
    opentile.WithTileSize(1024, 1024),                     // virtual tile size for OneFrame levels
    opentile.WithNDPISynthesizedLabel(false),              // disable the v0.2 NDPI label synthesis
)

For an io.ReaderAt source (S3, in-memory, etc.) instead of a filename:

t, err := opentile.Open(reader, size, opts...)
Reading tiles
base, _ := t.Level(0)

// Per-tile metadata.
fmt.Printf("base: %v tiles of %v pixels, compression %s, mpp %v\n",
    base.Grid, base.TileSize, base.Compression, base.MPP)

// Get one tile's raw compressed bytes.
tile, err := base.Tile(0, 0)

Stream a tile via io.ReadCloser:

rc, err := base.TileReader(0, 0)
defer rc.Close()
io.Copy(dst, rc)

Iterate every tile in row-major order:

for pos, res := range base.Tiles(ctx) {
    if res.Err != nil { /* ... */ }
    process(pos.X, pos.Y, res.Bytes)
}
Multi-image files

OME-TIFF can carry multiple main pyramids in a single file. s.Pyramids() returns them all; s.Levels() is a shortcut for the first pyramid's levels (s.Pyramids()[0].Levels) for callers that don't need to distinguish.

for _, pyr := range t.Pyramids() {
    l0, _ := pyr.Level(0)
    fmt.Printf("Pyramid %d (%q): %d levels, %v µm/px\n",
        pyr.Index, pyr.Name, len(pyr.Levels), l0.MPP)
    tile, _ := l0.Tile(0, 0)
    _ = tile
}

For SVS, NDPI, and Philips, Pyramids() always returns a one-element slice — Levels() / Level(i) work as before.

Reading pixel regions and scaled strips

The Tile* methods above return one tile's compressed bytes. For decoded pixels — arbitrary regions, downsampled output, or whole-slide streaming (DZI conversion, tile servers, region extract) — use the region/strip API. All of these return *decoder.Image (Width, Height, Stride, Format, Pix []byte).

// A decoded pixel region at a given level (level coords).
base, _ := t.Level(0)
img, err := base.ReadRegion(opentile.Region{
    Origin: opentile.Point{X: x, Y: y},
    Size:   opentile.Size{W: w, H: h},
})

// An L0 region scaled to an explicit output size. IDCT-time downscale
// + resample under the hood.
l0 := t.Levels()[0]
pyr := t.Pyramid(0)
region, err := pyr.ReadRegionScaled(
    opentile.Region{Size: l0.Size}, // full L0 extent
    opentile.Size{W: 1024, H: 1024},
)

// A whole-slide thumbnail/overview, rendered from the pyramid (a thin,
// aspect-preserving convenience over ReadRegionScaled). A zero axis is
// unconstrained, so one Size expresses fit-box / fit-width / fit-height:
thumb, err := t.RenderThumbnail(opentile.Size{W: 256, H: 256}) // fit inside 256×256
_, _ = t.RenderThumbnail(opentile.Size{W: 512})                // fit-width:  width 512, height from aspect
_, _ = t.RenderThumbnail(opentile.Size{H: 512})                // fit-height: height 512, width from aspect

RenderThumbnail always renders from the image pyramid (for BIF it is correctly stitched) and never upscales past L0. It is not the embedded thumbnail/overview — for the scanner's own associated images, use s.AssociatedImages().

// A synthesized macro: the tissue composited at its TRUE physical size
// (via MPP, or 10/objective-mag) and centred on a slide-shaped canvas —
// a macro-style orientation image for slides that don't embed one.
macro, err := s.RenderMacro(opentile.Size{W: 600}) // 600×300 slide canvas

For whole-slide scaled output that is too large to hold in memory at once — DZI/deep-zoom builders, libvips-style pipelines — iterate it in horizontal strips. ScaledStrips runs parallel decode workers + a bounded internal cache + lookahead prefetch; you pull one strip at a time:

l0 := t.Levels()[0]
pyr := t.Pyramid(0)
it := pyr.ScaledStrips(
    opentile.Region{Size: l0.Size},          // L0 region (here: whole slide)
    l0.Size,                                 // output size (here: native res)
    256,                                     // strip height in output rows
    // opts: WithStripWorkers, WithStripLookahead, WithStripKernel,
    // WithStripIDCTScale, WithStripContext
)
defer it.Close() // mandatory — reaps the worker goroutines

for {
    strip, err := it.Next()
    if err == io.EOF {
        break
    }
    if err != nil { /* ... */ }
    consume(strip) // strip is one *decoder.Image band, outSize.W wide
}

Peak memory for the strip path is bounded and independent of slide width — see Performance → Memory below for the budget knob and tuning.

Display tiles for rendering (StitchedTile)

For a tile-server / GPU viewer, render display tiles with StitchedTile over StitchedGrid() instead of DecodedTile over Grid. StitchedTile returns clean, non-overlapping display tiles — a true partition of the level's Size — composited from the stitched image with a per-source-tile decode-once cache. For the non-overlapping formats it is exactly DecodedTile, so a viewer treats every format uniformly.

l, _ := t.Level(0)
grid := l.StitchedGrid() // == ceil(Size/TileSize)
dst := decoder.NewImage(l.TileSize.W, l.TileSize.H)
for ty := 0; ty < grid.H; ty++ {
    for tx := 0; tx < grid.W; tx++ {
        _ = l.StitchedTileInto(tx, ty, dst) // dst reused; white-filled per call
        upload(dst)
    }
}

Overlapping levels (the #71 contract). For stitched BIF the raw tiles overlap, so Level.Grid does not tile Size and Level.Overlapping == true. Gate any verbatim per-tile copy (faithful transcode) on !Overlapping, and route pixel reassembly through StitchedTile / ReadRegion. Overlapping is false for every non-BIF format.

Caller-chosen display tile size (non-square tiles). On overlapping levels the display tile size is dst's own dimensions, so a viewer can render uniform/square tiles even though legacy BIF stores non-square 1024×1360 tiles. Pair a square dst with StitchedGridFor(tile):

disp := opentile.Size{W: 512, H: 512}   // square, independent of stored TileSize
grid := l.StitchedGridFor(disp)         // == ceil(Size/512)
dst := decoder.NewImage(disp.W, disp.H)
_ = l.StitchedTileInto(tx, ty, dst)     // 512×512 display tile == ReadRegion of that rect
Associated images

s.AssociatedImages() returns label / overview / thumbnail / map images where the format provides them:

for _, a := range t.AssociatedImages() {
    // Raw: compressed bytes as stored on disk.
    b, err := a.Bytes()
    if err != nil { continue }
    fmt.Printf("%s: %v, %s, %d bytes\n", a.Type(), a.Size(), a.Compression(), len(b))

    // Decoded: faithful RGB(A) pixels (needs `_ "…/decoder/all"`).
    img, err := a.Decode(decoder.DecodeOptions{}) // or {Format: decoder.PixelFormatRGBA}
    // img is *decoder.Image{Width, Height, Stride, Format, Pix}
}
  • a.Bytes() returns the compressed bytes in whatever codec the source carries (JPEG, LZW, …). For multi-strip LZW labels this is a re-encoded stream — use Decode if you need pixels.
  • a.Decode(opts) returns faithfully-decoded pixels for any codec (JPEG / JP2K / HTJ2K / WebP / AVIF / JPEG XL / LZW incl. Predictor=2 / Deflate / uncompressed), owning all codec / strip / predictor handling. Returns decoder.ErrCodecUnavailable when the codec isn't compiled in (e.g. JP2K under nojp2k).
  • a.Type() returns an AssociatedType"label", "overview", "thumbnail", "macro" (IFE), "map" (NDPI/IFE), "probability" (BIF/IFE), or "associated". Use typed constants opentile.AssociatedLabel, AssociatedOverview, AssociatedThumbnail, AssociatedMap, AssociatedProbability, AssociatedMacro, AssociatedGeneric rather than string literals.
  • a.Encoding() returns the on-disk encoded strips + TIFF tags so a consumer can re-emit the associated image into a fresh standalone single-IFD TIFF with no re-encode — byte-identical strip bytes plus the Compression / Predictor / JPEGTables / RowsPerStrip / Samples / Photometric tags needed to write a conforming IFD. ok=false for associated images with no faithful single-IFD strip form — self-contained JPEGs (use Bytes()), DICOM frames, OME planar pages, tiled, and synthesized labels.
Format-specific metadata

Cross-format fields (manufacturer, scanner serial, acquisition datetime, magnification) are surfaced via t.Metadata(). Format-specific fields are accessible by type-asserting through a per-format helper:

import (
    svs "github.com/wsilabs/opentile-go/formats/svs"
    ndpi "github.com/wsilabs/opentile-go/formats/ndpi"
    philips "github.com/wsilabs/opentile-go/formats/philips"
    ome "github.com/wsilabs/opentile-go/formats/ome"
)

if md, ok := svs.MetadataOf(t); ok {
    fmt.Println("MPP (SVS):", md.MPP, "µm/px")
}
if md, ok := ndpi.MetadataOf(t); ok {
    fmt.Println("source lens (NDPI):", md.SourceLens, "x")
}
if md, ok := philips.MetadataOf(t); ok {
    fmt.Println("PixelSpacing (Philips):", md.PixelSpacing, "mm")
}
if md, ok := ome.MetadataOf(t); ok {
    fmt.Println("OME images:", len(md.Images))
}

MetadataOf walks any number of wrapper Tilers (e.g., *fileCloser from OpenFile) before asserting on the concrete type, so the helper works regardless of how the Tiler was obtained.

Raw TIFF tags

For TIFF-based formats, raw tags — including vendor/private tags not surfaced as typed Metadata fields — are available per IFD, anchored to the level or associated image you already hold:

base, _ := slide.Level(0)
tags, ok := base.TIFFTags()                  // level-0 IFD tags
if ok {
    if tag, ok := tags.Tag(65420); ok {      // a vendor/private tag by number
        s, _ := tag.ASCII()
        _ = s
    }
}
a.TIFFTags()                                  // an associated image's tags
slide.TIFFDirectories()                       // every IFD incl. orphans (Map/hidden)

TIFFTag carries Number, best-effort Name, Type, Count, verbatim Raw bytes, and typed getters (ASCII/Uints/Rationals). Non-TIFF formats (IFE, SZI) return ok=false. Pixel-pointer tags (StripOffsets/TileOffsets/…) are excluded. Implemented for all TIFF-based formats (SVS, NDPI, Philips, OME-TIFF, BIF, generic-TIFF, Leica-SCN, COG-WSI).

Validating a slide

opentile.ValidateFile checks whether a WSI file is structurally well-formed without decoding any pixels:

rep, err := opentile.ValidateFile("slide.svs")
if err != nil { /* unreadable input */ }
if !rep.OK() {
    for _, f := range rep.Findings {
        fmt.Printf("%s [%s] %s (x%d)\n", f.Severity, f.Code, f.Message, f.Count)
    }
}

"OK" means well-formed per opentile-go's reader — not that pixels are correct or the file is fully spec-conformant. See docs/validate.md for the full check catalog, the four fences, and entry-point details.

Concurrency

Level.Tile, Level.TileInto, Level.TileAt, and Level.TileReader are safe to call concurrently from multiple goroutines. SVS / Philips / OME tiled / BIF / IFE have no internal locks on the tile hot path. NDPI's stripped reader takes a per-page mutex on its assembled-frame cache; concurrent reads of different pages run in parallel, concurrent reads of the same page serialize. OME OneFrame is similar.

All internal caches (parsed IFDs, per-tile offset / length tables, metadata) are populated at Open() time and then immutable — no locks on the tile hot path. Format packages with shared lazy caches use sync.Once and produce byte-deterministic output regardless of which goroutine populates them first.

Close() must not race with in-flight tile reads — drain before closing. Under the v0.9 default mmap backing, this is non-negotiable: closing unmaps the file, and subsequent reads through the mapping raise SIGBUS.

Performance

opentile-go's tile reads are designed for high-RPS HTTP serving and per-frame desktop viewers. See docs/perf.md for the full guide. Quick summary:

  • OpenFile is mmap-backed by default since v0.9. Tile reads become userspace memcpy; no pread(2) syscall per call. Opt out via opentile.WithBacking(opentile.BackingPread).
  • Use Level.TileInto(x, y, dst) (int, error) with a sync.Pool of []byte buffers sized to Level.TileMaxSize() for zero-allocation tile reads. Cervix serial: 152 ns/op, 0 allocs (vs v0.8's 22µs).
  • level.Warm() error pre-warms the page cache for predictable warm-cache latency.
  • Bandwidth deduplication (v0.13): Level.TilePrefix() returns the constant JPEG prefix; Level.TileBodyInto(x, y, dst) returns on-disk bytes without the prefix. Client-server consumers can send the prefix once per session and body bytes per tile. opentile.SpliceJPEGTile(prefix, body) reconstitutes a complete JPEG on the client side. Savings are fixture-author-dependent — see docs/perf.md for details.
Memory (ScaledStrips / DZI path)

The ScaledStrips decode path keeps a bounded internal cache of decoded source tiles. Since v0.30 that cache is byte-bounded, so peak memory is flat regardless of slide width — a 19-gigapixel NDPI slide and a 2-gigapixel one peak at roughly the same level.

  • opentile.WithMemoryBudget(bytes) — per-Slide budget for the read-path cache. Default 1 GiB. Also settable without recompiling via the OPENTILE_READ_MEMORY_BUDGET env var (bytes); the option wins over the env var, which wins over the default.
  • Set GOMEMLIMIT for the tightest peak. The budget bounds the live working set; Go's GC headroom (GOGC=100) lets the heap grow ~2× live before collecting. A GOMEMLIMIT (e.g. 2GiB) clamps that headroom — and when set, opentile-go's default budget auto-shrinks to ≤ half of it. opentile-go never sets GOMEMLIMIT itself.
  • Keep the DZI tile size at 256 (the default) for the lowest peak. Larger tiles (512/1024) need a proportionally larger full-width output strip buffer, which the cache budget does not cover.

Measured peak RSS on the widest test slide (Hamamatsu, 188k×101k px), worst case (no consumer backpressure):

Config peak RSS
256 tile + GOMEMLIMIT=2GiB (recommended) ~2.1 GB
256 tile, no env ~3.3 GB
1024 tile, no env (heaviest) ~5.8 GB

Even on a hypothetical maximum-size 2″×1″ 40× slide the recommended config stays ~2.3 GB; the absolute ceiling across all configs is ~7 GB. The peak is a fixed ceiling, not the unbounded climb of pre-v0.30. See docs/perf.md for the full breakdown.

Benchmarks & comparison

The repo carries a standing cross-format benchmark suite (bench/):

  • go test ./bench/ -bench BenchmarkRead — per-format throughput for Tile (compressed), DecodedTile, and ReadRegion, single and parallel, reporting Mpix/s + allocs/op. The profiling / A/B instrument (benchstat-friendly).
  • make bench-all — a local per-format throughput regression gate.
  • make bench-compare — an on-demand competitive report against openslide (decoded read_region) and Python opentile (compressed get_tile). Requires libopenslide + a python-opentile interpreter.

On the in-repo benchmark (one fixture per format, bounded interior grid, v0.34.1, 10-core Apple Silicon), opentile-go's decoded-region throughput is 3–14× openslide (e.g. generic-TIFF 14.3×, Philips 11.1×, SVS 9.5×, NDPI 3.2×). Raw compressed-tile fetch is ≈parity with Python opentile — both return the same compressed bytes, so it's an mmap-slice on both sides. These are single-machine, single-run figures; run make bench-compare for current numbers on your hardware, and see docs/perf.md for the full table, methodology, and caveats (region alignment, single machine, the multi-region SCN bounds offset).

Deviations from upstream Python opentile

opentile-go aims for byte-parity with Python opentile 0.20.0. A small number of deviations exist where matching upstream would encode an upstream oversight or where opentile-go provides a strictly more useful affordance:

Deviation Format Since Opt-out / API Why
Synthesised label NDPI v0.2 WithNDPISynthesizedLabel(false) Upstream doesn't surface NDPI labels at all; we crop the left 30% of the overview to provide an Aperio-style label affordance.
Map pages exposed NDPI v0.4 not opt-out-able (silent absence) tifffile already classifies them as series.name == 'Map'; surfacing matches the underlying TIFF carrying.
Multi-image OME pyramids OME v0.6 use s.Levels() instead of s.Pyramids() for first-pyramid-only behaviour Upstream's base Tiler loop silently drops 3 of 4 main pyramids in multi-image files via an unintentional last-wins assignment. We expose all of them via s.Pyramids().
Probability map exposed as type="probability" BIF v0.7 iterate s.AssociatedImages() and skip the type Upstream doesn't read BIF; openslide drops the probability map. We surface it for downstream tools that want it.
Level.TileOverlap field BIF + all v0.7 non-BIF formats return Point{} (zero) — no caller change needed BIF level-0 stores tiles with horizontal overlap; consumer needs the value to position raw tile bytes correctly.
Non-strict ScannerModel acceptance BIF v0.7 not opt-out-able The BIF spec mandates rejecting any slide whose ScannerModel != "VENTANA DP 200"; we accept any iScan-tagged TIFF (BigTIFF or classic, per #37) and route via HasPrefix("VENTANA DP") so legacy iScan slides aren't worse-than-openslide.
Multi-dimensional WSI API addition (TileCoord + Level.TileAt) All formats v0.7 additive — 2D-only formats return defaults Modern WSI consumers (fluorescence, focal-plane viewers, time series) need explicit multi-dim addressing. BIF reads multi-Z natively; full Z/C/T surface deferred to a future format-package milestone.
Non-TIFF dispatch path (FormatFactory.SupportsRaw + OpenRaw + RawUnsupported base) All formats v0.8 additive — TIFF factories embed RawUnsupported and inherit defaults Iris IFE is the first non-TIFF format opentile-go reads. Table-driven dispatch lets each format own its detection; future non-TIFF formats drop in additively.
TILE_TABLE.x_extent / y_extent ignored IFE v0.8 not opt-out-able The IFE v1.0 spec doc claims these fields carry image pixel dims, but the cervix fixture stores tile counts (matching LAYER_EXTENTS.x_tiles). Reader derives image dims from LAYER_EXTENTS × 256 instead — unambiguous either way.
Default mmap-backed OpenFile All formats v0.9 WithBacking(BackingPread) Universal perf win on the hot path (8–145× speedup; cervix serial Tile dropped from 22µs to 0.75µs). Auto-fallback to pread on mmap failure; SIGBUS on file truncation documented in the OpenFile docstring.
Level.TileInto + Level.TileMaxSize interface evolution All formats v0.9 additive — existing Tile() unchanged Pool-friendly tile-read API. With sync.Pool of []byte buffers sized to TileMaxSize(), the caller does zero allocations per tile on every TIFF format and IFE. NDPI / OME OneFrame still allocate internal scratch.
Level.Warm() interface evolution All formats v0.9 additive — hint operation, callers can ignore Page-cache pre-warm for predictable warm-cache latency. Useful for slide-server pre-warm at startup.
Generic-TIFF reader for non-vendor tiled pyramidal TIFFs Generic TIFF v0.10 not opt-out-able once registered; any TIFF that no vendor factory claims AND that passes the validator routes here Real-world WSI authoring outside Aperio / Hamamatsu / Philips is common (Grundium, Roche legacy iScan, vendor-stripped derivatives, libtiff-encoded research outputs). A catch-all reader makes opentile-go consume any structurally valid pyramid TIFF without per-vendor reverse-engineering.
"associated" AssociatedImage Type value addition Generic TIFF v0.10 iterate s.AssociatedImages() and skip the type Generic TIFFs may carry non-pyramid IFDs the heuristic classifier can't confidently match to label / macro / thumbnail; surfacing them as "associated" lets the consumer access Bytes() / Size() without a wrong-but-plausible type label.
Leica SCN reader for legacy SCN400 / SCN400F output Leica SCN v0.11 not opt-out-able once registered First real-fixture multi-region "discontinuous scanning" reader. Architecturally valuable beyond just SCN coverage.
Level.TilePrefix / TileBodyInto / TileBodyMaxSize + opentile.SpliceJPEGTile interface evolution All formats (JPEG splice formats benefit) v0.13 additive — existing Tile() / TileInto() unchanged Bandwidth-deduplication API for client-server consumers: send the per-level prefix once, send per-tile body bytes per request, reconstitute on client. Savings fixture-author-dependent (only slides with shared JPEGTables benefit).
Smart Zoom Image (SZI) reader Smart Zoom Image v0.16 not opt-out-able once registered First ZIP-backed format opentile-go reads; first format to surface CompressionPNG. Spec-mandated uncompressed-stored ZIP entries preserve the v0.9 mmap-aliased fast path. Backed by a new shared internal/dzi/ core designed for additive bare-DZI support in v0.17+.
COG-WSI reader + integer-multiple pyramid ratio acceptance COG-WSI + generic-TIFF v0.19 not opt-out-able once registered First spec-validated COG-profile reader opentile-go ships; pairs WSI-domain private tags 65080-87 + COG_WSI_VERSION ghost-area marker with the GDAL Cloud Optimized GeoTIFF base structure. Closes Issues #5 + #6. Generic-TIFF standalone benefit: relaxed strict-drift check now accepts clean integer-multiple pyramid ratios (Aperio / Grundium SVS-style 4×/2×/2× chains).

Full reasoning + per-deviation commit references are in docs/deferred.md.

Testing

make test     # go test ./... -race -count=1
make vet      # go vet ./...
make cover    # ≥80% per package; needs OPENTILE_TESTDIR
make parity   # batched parity oracle vs Python opentile 0.20.0 + tifffile
make bench    # NDPI per-tile throughput regression gate

Integration tests and the parity oracle require real slide files at $OPENTILE_TESTDIR. Fixture JSONs (committed) are at tests/fixtures/. Slides themselves are not redistributable and are gitignored.

OPENTILE_TESTDIR="$PWD/sample_files" go test ./tests/... -v

For parity testing against Python opentile + tifffile, set the Python interpreter and run with the parity build tag:

pip install -r tests/oracle/requirements.txt
OPENTILE_ORACLE_PYTHON=$(which python) \
OPENTILE_TESTDIR="$PWD/sample_files" \
  go test ./tests/oracle/... -tags parity -v

The default run samples ~100 tile positions per level per slide. A persistent stdin / stdout protocol keeps one Python subprocess resident per slide; full sweep on the v0.6 13-slide oracle slate completes in under 10 seconds.

License + attribution

Apache 2.0. Independent Go port of the Python opentile library (Copyright 2021–2024 Sectra AB); see NOTICE for attribution. Not affiliated with or endorsed by Sectra AB or the BigPicture project.

Documentation

Overview

Package opentile provides utilities to read tiles from whole-slide imaging (WSI) TIFF files. See the repository README for a high-level overview.

Index

Constants

View Source
const (
	// PropertyCaseNumber is the clinical / specimen case identifier.
	PropertyCaseNumber = "case-number"
	// PropertyUserName is the scan operator / user name.
	PropertyUserName = "user-name"
	// PropertyScannedAreaMM2 is the physical scanned area in mm²
	// (string-formatted float; parse via strconv.ParseFloat).
	PropertyScannedAreaMM2 = "scanned-area-mm2"
	// PropertyScanDurationSec is the wall-clock scan duration in
	// seconds (string-formatted float; parse via strconv.ParseFloat).
	PropertyScanDurationSec = "scan-duration-seconds"
	// PropertyComments is free-text user comments (distinct from
	// ImageDescription, which is the structured per-format description).
	PropertyComments = "comments"
)

PropertyXxx are the canonical opentile-go cross-format keys for Metadata.Properties. Format readers use these constants to populate well-known cross-format fields that don't have typed struct positions.

Added in v0.17.

Variables

View Source
var (
	ErrUnsupportedFormat      = errors.New("opentile: unsupported format")
	ErrUnsupportedCompression = errors.New("opentile: unsupported compression")
	ErrTileOutOfBounds        = errors.New("opentile: tile position out of bounds")
	ErrCorruptTile            = errors.New("opentile: corrupt tile")
	ErrLevelOutOfRange        = errors.New("opentile: level index out of range")
	ErrImageIndexOutOfRange   = errors.New("opentile: image index out of range")
	ErrInvalidTIFF            = errors.New("opentile: invalid TIFF structure")

	// ErrTooManyIFDs is returned when a TIFF IFD chain exceeds the safety cap
	// (1024 IFDs) before terminating. Either the file is corrupt, presents a
	// cycle, or is malicious. Re-exports internal/tiff.ErrTooManyIFDs so
	// callers can errors.Is(err, opentile.ErrTooManyIFDs).
	ErrTooManyIFDs = tiff.ErrTooManyIFDs

	// Returned (wrapped in TileError) when internal/jpeg cannot parse a JPEG
	// bitstream or assemble a valid one from TIFF fragments.
	ErrBadJPEGBitstream = errors.New("opentile: invalid JPEG bitstream")

	// Returned when an operation requires an MCU-aligned region and the
	// computed or requested region is not. Primarily an internal invariant
	// guard; consumers encounter it only on malformed slides.
	ErrMCUAlignment = errors.New("opentile: operation requires MCU alignment")

	// Returned from NDPI one-frame levels and NDPI label on builds compiled
	// without cgo (CGO_ENABLED=0 or -tags nocgo).
	ErrCGORequired = errors.New("opentile: operation requires cgo build with libjpeg-turbo")

	// Reserved for future use; currently unfired because v0.2 defaults the
	// NDPI tile size to 512 rather than erroring. Predefined so exporting
	// it later is not a breaking change.
	ErrTileSizeRequired = errors.New("opentile: tile size not representable for this format")

	// ErrDimensionUnavailable is returned (wrapped in TileError) when a
	// caller asks for a non-zero Z, C, or T axis on a TileCoord but the
	// underlying Image's SizeZ/SizeC/SizeT is 1 (the format / slide
	// doesn't carry that dimension at all). Distinct from
	// ErrTileOutOfBounds: that error means "this axis exists but the
	// requested index is past its size"; this means "the axis itself
	// doesn't exist on this slide / format / milestone."
	//
	// Added in v0.7 alongside Level.TileAt and the multi-dim Image
	// dimension accessors.
	ErrDimensionUnavailable = errors.New("opentile: dimension not supported on this format/image")

	// ErrSparseTile is returned (wrapped in TileError) when a tile
	// position falls within the level's grid but the underlying file
	// has no compressed bytes at that cell — the format encodes
	// "absent / blank tile" as a sentinel offset rather than empty
	// content. Iris IFE uses NULL_TILE (0xFFFFFFFFFF in the 40-bit
	// offset field); other formats may add later. Consumers typically
	// translate this into an HTTP 404 or a fixed blank image. Distinct
	// from ErrTileOutOfBounds (the position itself is past the grid).
	//
	// Added in v0.8 alongside the Iris IFE format package.
	ErrSparseTile = errors.New("opentile: sparse tile (no compressed bytes at this position)")

	// ErrMmapUnavailable is returned by [OpenFile] when called with
	// [WithBacking](BackingMmap) (the default since v0.9) but the
	// underlying memory-map operation fails — typically because the
	// file is on a filesystem that doesn't support mmap (some FUSE
	// or network mounts) or the platform lacks `golang.org/x/exp/mmap`
	// support. Wraps the underlying error from `mmap.Open`.
	//
	// Callers that want automatic fallback to the os.File / pread
	// path can retry with `opts...` extended by
	// `WithBacking(BackingPread)` on this error.
	//
	// Added in v0.9 alongside the mmap-default OpenFile change.
	ErrMmapUnavailable = errors.New("opentile: memory-map unavailable for this file")

	// ErrCodecNotRegistered is returned by Level.DecodedTile and friends
	// when no decoder is registered for the level's Compression. The
	// wrapping error message names the compression and the suggested
	// blank-import that fixes it.
	//
	// Added in v0.24 alongside the DecodedTile family.
	ErrCodecNotRegistered = errors.New("opentile: codec not registered for this slide's tile compression")

	// ErrRegionEmpty is returned by Level.ReadRegion / Pyramid.ReadRegionScaled
	// when the requested rectangle has no in-bounds pixels.
	//
	// Added in v0.25 alongside the ReadRegion family.
	ErrRegionEmpty = errors.New("opentile: region has no in-bounds pixels")
)
View Source
var ErrBadJPEGSplice = errors.New("opentile: bad JPEG splice input")

ErrBadJPEGSplice is returned by SpliceJPEGTile when the body bytes don't conform to the expected SOS-bearing JPEG layout.

Functions

func CompressionToTIFFTag added in v0.24.0

func CompressionToTIFFTag(c Compression) uint16

CompressionToTIFFTag returns the TIFF Compression tag value that corresponds to c, or 0 if no standard mapping exists. Used internally by Level.DecodedTile to dispatch through the decoder package's GetByCompressionTag registry.

CompressionIRIS and CompressionPNG return 0 because neither has a TIFF-registered decoder; DecodedTile surfaces ErrCodecNotRegistered for these.

func SetDICOMPathOpenHook added in v0.32.0

func SetDICOMPathOpenHook(fn func(path string) (any, error))

SetDICOMPathOpenHook registers the DICOM path-open function. Called once from formats/dicom's init() via factory.go. The hook receives a path (file or directory) and returns a slideReader (as any) or an error. If it returns ErrUnsupportedFormat the path is not DICOM and OpenFile falls through to the normal single-file dispatch. Not safe for concurrent use during setup.

This indirection avoids an import cycle: formats/dicom imports the root opentile package (for Level, Image, etc.); the root cannot import formats/dicom. The same pattern is used by internal/format (SetOpenAnyHook).

func SetDZIPathOpenHook added in v0.52.0

func SetDZIPathOpenHook(fn func(path string) (any, error))

SetDZIPathOpenHook registers the bare-DZI path-open function. Called once from formats/dzi's init().

func SetOpenAnyHook added in v0.23.0

func SetOpenAnyHook(fn func(
	r io.ReaderAt,
	size int64,
	tileSize Size,
	hasTileSize bool,
	corruptTilePolicy CorruptTilePolicy,
	ndpiSynthLabel bool,
	backing Backing,
) (any, error))

SetOpenAnyHook registers the format dispatch function. Called once from internal/format's init() via a bridge file. Must be called before any Open/OpenFile call. Not safe for concurrent use during setup.

func SpliceJPEGTile

func SpliceJPEGTile(prefix, body []byte) ([]byte, error)

SpliceJPEGTile reconstitutes a complete JPEG from a level's TilePrefix bytes and one tile's TileBodyInto output. Inserts the prefix at the on-disk tile's SOS boundary (the same operation opentile-go does internally during Tile/TileInto).

Returns body verbatim (defensively copied) if prefix is empty / nil — degenerate case for levels without splice (e.g., non-JPEG compressions, NDPI stripped levels, IFE).

Returns ErrBadJPEGSplice if body is empty or doesn't contain an SOS marker (0xFF 0xDA per JPEG spec).

Algorithm (documented for non-Go consumers reimplementing client-side):

  1. If prefix is empty: return body verbatim.
  2. Find offset of the first 0xFF 0xDA byte sequence in body ("Start of Scan" marker).
  3. Output = body[0:sosIdx] + prefix + body[sosIdx:]

Added in v0.13 alongside Level.TilePrefix and Level.TileBodyInto.

Types

type AssociatedEncoding added in v0.40.0

type AssociatedEncoding struct {
	Strips       [][]byte    // source strip bytes, in document order (written verbatim)
	Compression  Compression // tag 259
	Predictor    int         // tag 317 (1 none / 2 horizontal differencing)
	JPEGTables   []byte      // tag 347 (DQT/DHT); nil when absent or inline
	RowsPerStrip int         // tag 278
	Samples      int         // tag 277 SamplesPerPixel
	Photometric  int         // tag 262 PhotometricInterpretation
}

AssociatedEncoding is the on-disk encoded form of an associated image: the source IFD's strips plus the TIFF tags a consumer must set to re-emit them faithfully into a new standalone single-IFD TIFF — a byte-identical copy with NO re-encode (unlike AssociatedImage.Decode, which decodes to pixels, or Bytes, whose JPEG output is abbreviated and depends on the source IFD's JPEGTables).

To write a faithful standalone TIFF, set on a fresh IFD: ImageWidth/Length from a.Size(), BitsPerSample=8, SamplesPerPixel=Samples, PhotometricInterpretation=Photometric, Compression, RowsPerStrip, Predictor (tag 317, only if >1), JPEGTables (tag 347, only if non-nil), and StripOffsets/StripByteCounts pointing at the Strips written verbatim.

type AssociatedImage

type AssociatedImage interface {
	Type() AssociatedType
	Size() Size
	Compression() Compression
	Bytes() ([]byte, error)
	// Decode returns the faithfully-decoded pixels for this associated
	// image, honoring opts (Format RGB/RGBA; Scale on codec-backed images
	// only). Unlike Bytes() — which is a re-encoded, predictor-dropping
	// stream for LZW labels — Decode owns all codec / TIFF-strip / predictor
	// handling. Returns decoder.ErrCodecUnavailable when the codec isn't
	// compiled in (e.g. a JPEG 2000 image under a nojp2k build).
	Decode(opts decoder.DecodeOptions) (*decoder.Image, error)

	// Encoding returns the on-disk encoded form (source strips + TIFF tags)
	// for byte-identical re-emission into a new standalone single-IFD TIFF
	// without re-encoding. ok=false for non-TIFF, non-strip, or synthesized
	// associated images (DICOM frames, IFE, SZI, NDPI synthesized label,
	// OME-TIFF planar pages, Leica SCN tiled).
	Encoding() (AssociatedEncoding, bool)

	// TIFFTags returns the parsed TIFF tags of this associated image's
	// backing IFD. ok=false for non-TIFF formats (DICOM, IFE, SZI) and
	// for implementations that don't retain a page reference.
	TIFFTags() (TIFFTags, bool)

	// IFDOffset returns the byte offset of the IFD backing this associated
	// image, for in-place TIFF editing (e.g. raw IFD splice/replace).
	// ok=false for non-TIFF formats, non-strip associated images, and
	// formats where the implementation doesn't record the offset
	// (currently only SVS and generic-TIFF return ok=true).
	IFDOffset() (int64, bool)
}

AssociatedImage is a non-pyramidal slide-level image (label, overview, thumbnail).

Standard Type() values used across opentile-go's format readers. The choice of names follows DICOM PS3.3 / Supplement 145 (Whole Slide Microscopic Image IOD), where the Image Type attribute (0008,0008) value 3 enumerates: VOLUME / LABEL / OVERVIEW / THUMBNAIL. opentile-go uses the lowercase form, extended with format-specific types where the underlying file surfaces them:

"label"       — slide label / barcode
"overview"    — wide-field image of the slide. The DICOM-canonical
                term, also used by upstream Python opentile and by
                six of opentile-go's eight format readers. The
                seventh (Iris IFE) intentionally distinguishes
                "overview" from "macro" per the IFE spec.
"thumbnail"   — full-slide downsample (typically square, JPEG)
"map"         — NDPI / IFE: low-magnification map / overview-of-
                pyramid; semantically distinct from a wide-field
                slide image
"probability" — Ventana BIF / IFE: confidence / classification map
"macro"       — Iris IFE only. The IFE spec defines LABEL_MACRO
                as a type distinct from LABEL_OVERVIEW. Other
                formats' wide-field slide images surface as
                "overview", not "macro".
"associated"  — generic-TIFF heuristic-fallback (v0.10+) when the
                classifier can't confidently match a type above

Format readers use the exported AssociatedType constants; the values above are stable and part of the public API contract from v0.15 onward.

type AssociatedType added in v0.41.0

type AssociatedType string

AssociatedType is the type of an associated image (label, overview, thumbnail, etc.). The underlying value is the lowercase string surfaced by AssociatedImage.Type(). Use the AssociatedLabel / AssociatedOverview / … constants for comparisons.

const (
	AssociatedLabel       AssociatedType = "label"       // slide label / barcode
	AssociatedOverview    AssociatedType = "overview"    // wide-field image of the slide
	AssociatedThumbnail   AssociatedType = "thumbnail"   // full-slide downsample
	AssociatedMap         AssociatedType = "map"         // NDPI / IFE low-magnification map
	AssociatedProbability AssociatedType = "probability" // BIF / IFE confidence map
	AssociatedMacro       AssociatedType = "macro"       // Iris IFE only (distinct from overview)
	AssociatedGeneric     AssociatedType = "associated"  // generic-TIFF heuristic fallback
)

Standard AssociatedImage.Type() values returned by Type() across all format readers (documented on AssociatedImage above). Exported so consumers can switch/compare against named constants instead of hardcoding the literals. The set is open — a format reader may surface an additional value — so this is a naming convention, not a closed enum.

type Backing

type Backing uint8

Backing identifies the I/O backend used to read tile bytes from a slide file. Selectable via WithBacking; defaults to BackingMmap since v0.9.

BackingMmap memory-maps the file read-only and reads tiles via userspace memcpy from the mapped region. No syscall per Tile() call once the kernel has paged in the relevant region. Recommended for high-RPS serving and warm-cache desktop use. Caveat: SIGBUS on file truncation; not suitable for storage that gets rewritten underneath open Tilers.

BackingPread keeps the v0.8 (and earlier) os.File-based path: pread(2) syscall per Level.Tile call. Use this on filesystems that don't support mmap (some FUSE / network mounts), or when you specifically need the os.File semantics around truncation.

const (
	// BackingMmap memory-maps the slide file. Default since v0.9.
	BackingMmap Backing = iota
	// BackingPread uses os.File + pread(2) per Tile().
	BackingPread
)

type CheckCode added in v0.45.0

type CheckCode string

CheckCode is a stable, human-meaningful category of validation problem — the "general nature" of a Finding and the primary thing callers branch on. String-underlying so the catalog is open-ended (new codes are additive).

const (
	CheckUnopenable         CheckCode = "unopenable"
	CheckOffsetsOutOfBounds CheckCode = "offsets-out-of-bounds"
	CheckTileGridMismatch   CheckCode = "tile-grid-mismatch"
	// CheckNonConformantFormat is reserved: no reader emits it in v1 (COG-WSI
	// conformance is enforced fatally at Open). Kept for future per-format soft checks.
	CheckNonConformantFormat CheckCode = "non-conformant-format"
	CheckInconsistentPyramid CheckCode = "inconsistent-pyramid"
	CheckMissingMetadata     CheckCode = "missing-metadata"
	// CheckOrphanIFD is reserved: orphan-IFD detection is wired off in v1 (the
	// TIFF hooks pass an always-reachable predicate). Kept for when a reachability
	// map is added.
	CheckOrphanIFD CheckCode = "orphan-ifd"
)

type Compression

type Compression uint8

Compression identifies the bitstream format of a tile as stored in a TIFF.

opentile-go returns tile bytes in the compression format of the source TIFF without decoding them. Consumers that need decoded pixels should pass the bytes to a codec appropriate for the reported compression.

The zero value is CompressionUnknown: a forgotten-to-initialize field surfaces loudly rather than masquerading as a known compression.

const (
	CompressionUnknown Compression = iota // zero value; unset or unrecognized
	CompressionNone
	CompressionJPEG
	CompressionJP2K
	CompressionLZW  // TIFF tag 259 value 5 (Aperio SVS label is commonly LZW)
	CompressionAVIF // tile bytes are an AVIF image; consumer decodes via libavif
	// CompressionIRIS is the Iris-proprietary tile codec used by IFE files
	// when written through Iris-Codec. opentile-go reports it but does not
	// decode the bytes; consumers either embed an Iris codec or 501 the
	// request. JPEG and AVIF tiles in IFE remain decodable by external
	// codecs.
	CompressionIRIS
	// CompressionDeflate identifies the Deflate (zlib) bitstream
	// commonly used by scientific imaging TIFFs and the
	// generic-TIFF catch-all reader (v0.10). TIFF tag 259 values
	// 8 (Deflate) and 32946 (Adobe Deflate) both map here; the
	// payload is identical zlib-wrapped DEFLATE either way.
	CompressionDeflate
	// CompressionWebP identifies a WebP-encoded tile (RIFF + WEBP +
	// VP8/VP8L/VP8X chunks). TIFF tag 259 value 50001 in libtiff
	// convention; same value is what the user's wsi-tools transcoder
	// emits. Tile bytes are a complete self-contained WebP file.
	// Consumer decodes via libwebp or golang.org/x/image/webp.
	//
	// Added in v0.14.
	CompressionWebP
	// CompressionJPEGXL identifies a JPEG XL codestream tile. TIFF
	// tag 259 value 50002 (wsi-tools convention; not formally
	// registered). Tile bytes are a bare JXL codestream beginning
	// with the 0xFF 0x0A marker. Consumer decodes via libjxl (cgo)
	// or stdlib image/jxl when available.
	//
	// Added in v0.14.
	CompressionJPEGXL
	// CompressionHTJ2K identifies an HTJ2K (High-Throughput JPEG
	// 2000, ISO/IEC 15444-15) codestream tile. TIFF tag 259 value
	// 60003 (wsi-tools convention). Distinct from CompressionJP2K
	// because HTJ2K uses a different entropy coder (FBCOT instead
	// of EBCOT) and a standard JP2K decoder will fail on HTJ2K
	// bytes. Consumer decodes via OpenJPEG 2.5+, OpenHTJ2K, or
	// Kakadu.
	//
	// Added in v0.14.
	CompressionHTJ2K
	// CompressionPNG identifies a PNG-encoded tile (`\x89PNG` magic).
	// DZI's Format attribute admits both jpeg and png. Tile bytes
	// are a complete self-contained PNG file. Consumer decodes via
	// `image/png` (stdlib).
	//
	// Added in v0.16.
	CompressionPNG
)

func (Compression) String

func (c Compression) String() string

type Config

type Config struct {
	// contains filtered or unexported fields
}

Config is an opaque, read-only view of the configuration passed to a FormatFactory. Format packages import opentile.Config rather than the unexported config struct.

func NewTestConfig deprecated

func NewTestConfig(tileSize Size, policy CorruptTilePolicy) *Config

NewTestConfig constructs a Config for use in tests.

Deprecated: use opentile/opentiletest.NewConfig. Retained for compatibility; slated for removal in the coordinated v1.0 API pass.

func (*Config) Backing

func (c *Config) Backing() Backing

Backing reports the I/O backing the caller selected via WithBacking. Defaults to BackingMmap since v0.9 if no option was passed. Format packages typically don't need this — Open is path-agnostic — but it's exposed for diagnostic accessors.

func (*Config) CorruptTilePolicy

func (c *Config) CorruptTilePolicy() CorruptTilePolicy

CorruptTilePolicy returns the configured policy.

func (*Config) NDPISynthesizedLabel

func (c *Config) NDPISynthesizedLabel() bool

NDPISynthesizedLabel reports whether NDPI Tiler.AssociatedImages() should include a synthesized label cropped from the overview. Default true.

func (*Config) TileSize

func (c *Config) TileSize() (Size, bool)

TileSize returns the requested output tile size and whether the caller set one.

  • (Size{}, false): caller did not pass WithTileSize. Format packages should use their format default (e.g. SVS reads the native tile size from the TIFF; NDPI uses 512).
  • (Size{}, true): caller explicitly passed WithTileSize(0, 0). Format packages MUST reject this as malformed input. The zero Size is distinct from "unset" because the API contract is that an explicit option overrides the default.
  • (non-zero, true): caller's requested tile size; format honors it (NDPI may snap to a stripe-multiple, SVS rejects when it doesn't match the native tile dimensions).

type CorruptTilePolicy

type CorruptTilePolicy uint8

CorruptTilePolicy controls how corrupt-edge tiles (currently: Aperio SVS) are reported. v0.1 supports only CorruptTileError.

const (
	CorruptTileError CorruptTilePolicy = iota // return ErrCorruptTile (default, v0.1)
	CorruptTileBlank                          // v0.3: return a typed blank tile
	CorruptTileFix                            // v1.0: reconstruct from parent level
)

type DecodeOption added in v0.24.0

type DecodeOption func(*decodeConfig)

DecodeOption configures a Level.DecodedTile / DecodedTileInto / ReadRegion or Pyramid.ReadRegionScaled call. See WithFormat, WithScale, WithResampleKernel.

func WithFormat added in v0.24.0

func WithFormat(f decoder.PixelFormat) DecodeOption

WithFormat sets the requested output pixel format. Defaults to PixelFormatRGB (3 bytes per pixel; alpha-free). PixelFormatRGBA is also universally supported.

func WithResampleKernel added in v0.25.0

func WithResampleKernel(k resample.Kernel) DecodeOption

WithResampleKernel chooses the resample kernel for ReadRegionScaled. Has no effect on ReadRegion (no resampling step).

resample.Lanczos  — best perceptual quality (default)
resample.Box      — fast integer-ratio downsampling, sharp
resample.Bilinear — fast, decent quality
resample.Nearest  — fastest, ugly under downsampling

func WithScale added in v0.24.0

func WithScale(s int) DecodeOption

WithScale sets the in-codec downscale factor, decoding to ceil(dim/scale). Valid values: 1, 2, 4, 8. Honored by jpeg (IDCT fast-scale), jpeg2000 (cp_reduce) and htj2k (restrict_input_resolution); other codecs return ErrUnsupportedScale for scale != 1.

type DirectoryType added in v0.35.0

type DirectoryType uint8

DirectoryType classifies a TIFF IFD's semantic role.

const (
	DirOther      DirectoryType = iota // hidden / Map / SubIFD not surfaced elsewhere
	DirLevel                           // a pyramid level
	DirAssociated                      // an associated image
)

type Finding added in v0.45.0

type Finding struct {
	Severity Severity
	Code     CheckCode
	Message  string // human context, e.g. "200 tiles reference offsets past EOF"
	Pyramid  int    // coarse locus; -1 when whole-file / not applicable
	Level    int    // coarse locus; -1 when not applicable
	Count    int    // occurrences rolled up under this (Code, locus); >= 1
}

Finding is one rolled-up validation problem. Many occurrences of the same (Code, locus) are aggregated into a single Finding with a Count — the report conveys the general nature and scale, not a per-occurrence repair list.

type Format

type Format string

Format identifies the source file format.

const (
	FormatSVS  Format = "svs"
	FormatNDPI Format = "ndpi"
	// FormatPhilipsTIFF is the Philips IntelliSite Pathology Solution TIFF
	// reader. Renamed in v0.12 from FormatPhilips to FormatPhilipsTIFF to
	// align with v0.10's FormatGenericTIFF and v0.11's FormatLeicaSCN naming
	// convention; Philips has multiple WSI file formats (TIFF; iSyntax), so
	// the bare "philips" identifier was ambiguous. Reports as "philips-tiff".
	FormatPhilipsTIFF Format = "philips-tiff"
	// FormatOMETIFF is the OME-TIFF reader. Renamed in v0.12 to align
	// with v0.10/v0.11's FormatGenericTIFF / FormatLeicaSCN convention;
	// OME has multiple file formats (OME-TIFF, OME-Zarr, OME-NGFF), so
	// the bare "ome" identifier ambiguously claimed the family.
	FormatOMETIFF Format = "ome-tiff"
	FormatBIF     Format = "bif"
	FormatIFE     Format = "ife"
	// FormatGenericTIFF is the catch-all reader for tiled pyramidal TIFF
	// without vendor metadata (added in v0.10). Activates when no
	// vendor format factory claims the file. Reports as "generic-tiff"
	// to differentiate from possible future generic-non-TIFF readers.
	FormatGenericTIFF Format = "generic-tiff"
	// FormatLeicaSCN is the Leica SCN reader (added in v0.11). SCN is a
	// BigTIFF dialect produced by Leica SCN400 / SCN400F scanners;
	// scanner production stopped ~2015. Reports as "leica-scn" to
	// differentiate from other Leica-related formats (LIF, LMS) that
	// aren't SCN.
	FormatLeicaSCN Format = "leica-scn"
	// FormatSZI identifies a Smart Zoom Image file (ZIP-wrapped
	// Microsoft Deep Zoom pyramid + scan-properties.xml +
	// associated_images/, per the smartinmedia/SZI-Format spec).
	//
	// Added in v0.16.
	FormatSZI Format = "szi"
	// FormatCOGWSI identifies a Cloud Optimized GeoTIFF for WSI file —
	// a strict extension of GDAL Cloud Optimized GeoTIFF carrying
	// WSI-specific private tags + ghost-area marker. Spec at
	// docs/specs/2026-05-20-cog-wsi-format.md. Added in v0.19.
	FormatCOGWSI Format = "cog-wsi"
	// FormatDICOM identifies a DICOM VL Whole Slide Microscopy Image Storage
	// series (one directory of .dcm instances per series). The first multi-file
	// format in opentile-go; opened via OpenFile(directoryPath). Added in v0.32.
	FormatDICOM Format = "dicom"
	// FormatDZI identifies a bare Deep Zoom Image — a filesystem .dzi XML
	// manifest plus a sibling <name>_files/<level>/<col>_<row>.<ext> tile tree
	// (the OpenSeadragon / Microsoft Deep Zoom layout). Unlike SZI (a ZIP
	// wrapper), bare DZI is opened from a path via OpenFile (the .dzi file or a
	// directory containing exactly one), like DICOM. Overlap=0 only. Added in v0.52.
	FormatDZI Format = "dzi"
	// FormatUnknown is the zero value of Format, used when a file did not
	// open as any known format (e.g. Report.Format on an Unopenable file).
	FormatUnknown Format = ""
)

type Level

type Level struct {
	// Index is the 0-based index of this level within the parent
	// Pyramid's Levels slice.
	Index int

	// PyramidIndex is the pyramid-group index for multi-image formats.
	// Single-image formats always have PyramidIndex = 0. OME-TIFF
	// multi-image files preserve the per-image series identifier here.
	PyramidIndex int

	// Size is the pixel dimensions of this level (Width × Height).
	Size Size

	// TileSize is the tile dimensions used by this level.
	TileSize Size

	// Grid is the tile grid dimensions: ceil(Size / TileSize) per axis
	// for ordinary (non-overlapping) levels. Pre-computed for convenience.
	//
	// IMPORTANT: when OverlapMode == OverlapStitched (a stitched BIF level),
	// Grid is the RAW stored tile grid of OVERLAPPING tiles and does NOT tile
	// Size — Grid.W × TileSize.W > Size.W. Per-tile reads address those raw
	// overlapping tiles at their stored positions, NOT a clean partition of the
	// stitched image; use the region API to reassemble pixels. For
	// OverlapBordered (DZI/SZI overlap>0) and OverlapNone, Grid DOES tile Size.
	// See Overlapping / OverlapMode.
	Grid Size

	// OverlapMode classifies this level's tile/grid relationship:
	// OverlapNone (clean partition), OverlapBordered (DZI/SZI overlap>0 —
	// tiles padded with a croppable border; Grid still tiles Size), or
	// OverlapStitched (BIF — compacted hull; Grid does NOT tile Size).
	// Overlapping == (OverlapMode != OverlapNone).
	OverlapMode OverlapMode

	// Overlapping is a convenience equal to (OverlapMode != OverlapNone):
	// stored/decoded tiles carry an overlap region — a padded border for
	// OverlapBordered, raw overlapping frames for OverlapStitched — so a
	// per-tile read is NOT a verbatim TileSize content cell. Treat per-tile
	// reads as a clean partition of Size only when !Overlapping; otherwise use
	// the region API, or (OverlapBordered) crop each decoded tile to
	// TileContentRect. For the precise flavour — and specifically whether Grid
	// tiles Size (only OverlapStitched does not) — read OverlapMode.
	Overlapping bool

	// TileOverlap is the per-tile overlap magnitude. For OverlapBordered it is
	// {ov, ov} (the DZI Overlap attribute; non-zero for a conformant overlapped source). For OverlapStitched
	// it is the BIF L0 magnitude where one is meaningful, but {0,0} on BIF
	// reduced levels (per-frame placement is authoritative there). Zero for
	// OverlapNone. NOT a reliable overlap test — gate on Overlapping/OverlapMode.
	TileOverlap Point

	// Compression identifies the codec for tile bytes at this level.
	// Used by l.DecodedTile to dispatch to the right decoder.
	Compression Compression

	// MPP is microns-per-pixel at this level (X and Y; usually equal).
	// Zero value (MPP.IsZero() == true) when the slide doesn't carry
	// per-level MPP metadata. Values are in microns, not millimeters.
	//
	// Changed from SizeMm (millimeters) to MPP (microns) in v1.0.
	MPP MPP

	// FocalPlane is the z-position in microns for multi-focal-plane
	// sources. Zero value for 2D slides.
	FocalPlane float64

	// Downsample is the resolution factor from L0. 1.0 at level 0,
	// 2.0 at half-resolution, 4.0 at quarter, etc. Computed at Open
	// time from the level's Size relative to the image's L0 Size.
	//
	// Used by p.BestLevelForDownsample and p.ReadRegionScaled
	// to translate L0 coords into level coords.
	//
	// Added in v0.25 alongside the ReadRegion family.
	Downsample float64
	// contains filtered or unexported fields
}

Level is one resolution tier of a Pyramid. Its exported fields are inspection-only metadata (read at Open time); tile and region reads are methods on *Level (l.Tile, l.DecodedTile, l.ReadRegion, l.Tiles, ...). Obtain a *Level via s.Level(i), s.Levels(), or p.Level(i).

func (*Level) DecodedTile added in v0.41.0

func (l *Level) DecodedTile(tx, ty int, opts ...DecodeOption) (*decoder.Image, error)

DecodedTile returns the decoded pixels for the tile at (tx, ty).

func (*Level) DecodedTileInto added in v0.41.0

func (l *Level) DecodedTileInto(tx, ty int, dst *decoder.Image, opts ...DecodeOption) error

DecodedTileInto decodes the tile at (tx, ty) into the caller-provided dst.

func (*Level) ReadRegion added in v0.41.0

func (l *Level) ReadRegion(r Region, opts ...DecodeOption) (*decoder.Image, error)

ReadRegion returns the decoded pixels for rectangle r at this level's own resolution.

func (*Level) ReadRegionInto added in v0.41.0

func (l *Level) ReadRegionInto(origin Point, dst *decoder.Image, opts ...DecodeOption) error

ReadRegionInto decodes a region into the caller-provided dst. origin is at this level's resolution; the region size is taken from dst.

func (*Level) StitchedGrid added in v0.50.0

func (l *Level) StitchedGrid() Size

StitchedGrid is the canonical display grid, ceil(Size/TileSize) per axis — a clean partition of Size. Equals Grid for non-overlapping levels; for an overlapping level it is the grid that tiles Size (whereas Grid stays the raw overlapping grid). Iterate StitchedGrid with StitchedTile to render.

func (*Level) StitchedGridFor added in v0.57.0

func (l *Level) StitchedGridFor(tile Size) Size

StitchedGridFor is StitchedGrid for a caller-chosen display tile size: ceil(Size/tile) per axis. Iterate it with StitchedTileInto using a tile-sized dst to render display tiles at a uniform/square size independent of the stored (possibly non-square) TileSize — e.g. legacy BIF stores 1024×1360 but a viewer can render 512×512. The caller-chosen size is honored on overlapping levels; on non-overlapping levels StitchedTileInto still requires dst == TileSize, so use StitchedGrid there. Returns the zero Size for a non-positive tile.

func (*Level) StitchedTile added in v0.50.0

func (l *Level) StitchedTile(tx, ty int, opts ...DecodeOption) (*decoder.Image, error)

StitchedTile returns a clean, non-overlapping display tile from the canonical grid StitchedGrid() (== ceil(Size/TileSize)). For overlapping levels (Overlapping == true: stitched BIF) it composites the stitched image so the returned tile is a true partition of Size; for every other format it is exactly DecodedTile. Pixels match ReadRegion over the tile's rectangle.

Use this (with StitchedGrid) for display/rendering. Use Tile / DecodedTile + Grid only when you want the raw stored (possibly overlapping) tiles, e.g. for faithful transcoding. Scale > 1 is unsupported on overlapping levels (use the Pyramid's ReadRegionScaled / ScaledStrips); it returns ErrUnsupportedScale.

func (*Level) StitchedTileInto added in v0.51.0

func (l *Level) StitchedTileInto(tx, ty int, dst *decoder.Image, opts ...DecodeOption) error

StitchedTileInto is the allocation-free form of StitchedTile: it composites the display tile (tx, ty) into the caller-provided dst. The composite is done in dst's own pixel format, and dst is white-filled before compositing. Reuse one dst across a display-grid traversal to avoid a per-tile allocation.

The DISPLAY TILE SIZE is dst's own dimensions: for an OVERLAPPING level (stitched BIF) the composite is region-based, so dst may be any size — a viewer can render uniform/square display tiles (e.g. 512×512) even though the level stores non-square tiles (legacy BIF is 1024×1360). Pair it with StitchedGridFor(dstSize) for the matching iteration grid; the result is pixel-identical to ReadRegion over [tx*dst.W, ty*dst.H, dst.W, dst.H]. For a NON-overlapping level it behaves like DecodedTileInto, so dst must be the level's TileSize (retiling other formats to a custom size is not in scope — they store square tiles; use ReadRegion for an arbitrary rectangle).

func (*Level) TIFFTags added in v0.41.0

func (l *Level) TIFFTags() (TIFFTags, bool)

TIFFTags returns the parsed TIFF tags of this level's backing IFD. ok=false for non-TIFF formats.

func (*Level) Tile

func (l *Level) Tile(tx, ty int) ([]byte, error)

Tile returns the compressed tile bytes at tile coordinates (tx, ty).

func (*Level) TileBodyInto

func (l *Level) TileBodyInto(tx, ty int, dst []byte) (int, error)

TileBodyInto fills dst with the tile body bytes (no prefix) at (tx, ty).

func (*Level) TileBodyMaxSize

func (l *Level) TileBodyMaxSize() int

TileBodyMaxSize returns the upper bound on tile-body (no prefix) byte size at this level.

func (*Level) TileContentRect added in v0.60.0

func (l *Level) TileContentRect(col, row int) (Region, bool)

TileContentRect returns the content sub-rectangle within the decoded tile (col,row) — its in-tile origin and size. For OverlapBordered levels the origin is the overlap border to skip ((col>0?ov:0, row>0?ov:0)) and the size is the content cell clipped at the level's right/bottom edge; a consumer crops a decoded tile to this rect to drop the redundant overlap. For OverlapNone it is the full clipped cell at origin (0,0) — a universal "where is the real content" answer. ok is false for OverlapStitched (Grid does not tile Size — use the region API) and for an out-of-grid (col,row).

func (*Level) TileInto

func (l *Level) TileInto(tx, ty int, dst []byte) (int, error)

TileInto fills dst with the compressed tile bytes at (tx, ty) and returns the byte count written.

func (*Level) TileMaxSize

func (l *Level) TileMaxSize() int

TileMaxSize returns the upper bound on compressed tile byte size at this level — for sizing buffers passed to TileInto.

func (*Level) TilePrefix

func (l *Level) TilePrefix() []byte

TilePrefix returns the shared codec prefix (e.g. JPEG tables) for this level, or nil if the codec has no prefix.

func (*Level) TileReader

func (l *Level) TileReader(tx, ty int) (io.ReadCloser, error)

TileReader returns a streaming reader for the compressed tile at (tx, ty).

func (*Level) Tiles

func (l *Level) Tiles(ctx context.Context) iter.Seq2[Point, TileResult]

Tiles returns a row-major range-over-function iterator over all tiles at this level.

func (*Level) Warm added in v0.41.0

func (l *Level) Warm() error

Warm pre-warms the page cache for this level. Hint-only.

type MPP added in v0.41.0

type MPP struct{ X, Y float64 }

MPP is microns-per-pixel, per axis. The zero value means "unknown". Most slides report isotropic pixels (X == Y); asymmetric formats (e.g. some Philips TIFF fixtures) populate both axes independently.

Added in v1.0.

func (MPP) IsZero added in v0.41.0

func (m MPP) IsZero() bool

IsZero reports whether the MPP is unknown (both axes zero).

func (MPP) Symmetric added in v0.41.0

func (m MPP) Symmetric() float64

Symmetric returns the single µm/px value when both axes are equal and non-zero. Returns 0 when X != Y or when both are zero (unknown).

type Metadata

type Metadata struct {
	Magnification       float64 // 0 if unknown
	ScannerManufacturer string
	ScannerModel        string
	ScannerSoftware     []string
	ScannerSerial       string
	// AcquisitionDateTime is the time the slide was scanned. Partial Date
	// or Time values that fail time.Parse yield the zero value
	// (time.Time{}); time.Time{}.IsZero() == true is the "unknown"
	// sentinel. Callers should always check IsZero rather than comparing
	// against a specific time — different scanner vendors emit dates in
	// different formats and our parsers are lenient but not exhaustive.
	AcquisitionDateTime time.Time

	// MPP is the per-axis microns-per-pixel for this slide.
	// The zero value (MPP.IsZero() == true) means the format didn't
	// report it. Most slides are isotropic (MPP.X == MPP.Y);
	// MPP.Symmetric() returns the single value when X == Y, else 0.
	//
	// Replaces the three MicronsPerPixel / MicronsPerPixelX /
	// MicronsPerPixelY float64 fields from v0.17–v0.39 in v1.0.
	MPP MPP

	// ImageDescription is the structured per-format description (e.g.,
	// SVS ImageDescription TIFF tag, OME-XML <Image Description>
	// attribute). Empty when the format has no equivalent. For free-
	// text user comments, see Properties[PropertyComments].
	//
	// Added in v0.17.
	ImageDescription string

	// Properties is a flat key-value map for additional metadata
	// that doesn't fit the typed fields. Two key conventions:
	//
	//   - opentile-go-canonical keys (lowercase-with-hyphens):
	//     PropertyCaseNumber, PropertyUserName, PropertyScannedAreaMM2,
	//     PropertyScanDurationSec, PropertyComments. Populated by
	//     format readers when their format exposes the equivalent.
	//
	//   - vendor-namespaced keys (vendor.<key>): vendor-specific
	//     fields surfaced as-is. Format-prefixed: e.g., "szi.vendor.
	//     SerialNumber", "aperio.AppMag".
	//
	// Missing keys mean the format didn't expose that field. Numeric
	// values are string-formatted floats (parseable via
	// strconv.ParseFloat).
	//
	// Added in v0.17.
	Properties map[string]string

	// Writer identifies the software that wrote this file — the
	// file producer, distinct from ScannerManufacturer (scanner OEM)
	// and ScannerSoftware []string (broader software stack).
	//
	// Format-specific population:
	//   SVS Aperio canonical    "Aperio Image Library v11.2.1"
	//   SVS Grundium / other    "Grundium Ocus" (comma-suffix writer
	//                            from v0.18 detection)
	//   OME-TIFF                "OME Bio-Formats 6.0.0-rc1" (Creator
	//                            attribute; promoted from Properties)
	//   SZI                     "<SoftwareName> <SoftwareVersion>"
	//                            (e.g., "OcusScan 3.1.4")
	//   COG-WSI                 "wsitools/<WSIToolsVersion>" (file
	//                            producer; source scanner stays in
	//                            ScannerManufacturer per spec)
	//   Generic-TIFF (wsi-tools  "wsitools/<version>" from the
	//     fixtures avif/jxl/      wsi-tools ImageDescription parser
	//     htj2k/webp)
	//   NDPI / Philips / BIF /  format-specific Software field (often
	//     IFE / Leica SCN        equals ScannerSoftware[0])
	//
	// Empty when the format provides no writer indication. Consumers
	// checking presence compare against "" explicitly.
	//
	// Added in v0.20.
	Writer string
}

Metadata is the common subset of slide metadata surfaced across all formats. Format packages embed this struct to add format-specific fields exposed via type assertion on Tiler.Metadata().

func (*Metadata) SetMPPSymmetric

func (m *Metadata) SetMPPSymmetric()

SetMPPSymmetric is a shim for readers that set per-axis MPP fields before v1.0. It is now a no-op: readers should set md.MPP = MPP{X: µmX, Y: µmY} directly. Kept to avoid churn; removed in a future cleanup pass.

Added in v0.17; deprecated in v1.0.

func (*Metadata) SetProperty

func (m *Metadata) SetProperty(key, value string)

SetProperty is a nil-safe setter for Properties. Lazily initializes the map on first use.

Added in v0.17.

type Option

type Option func(*config)

Option mutates the opentile configuration before Open returns a Tiler.

func WithBacking

func WithBacking(b Backing) Option

WithBacking selects the I/O backend used by OpenFile. The default since v0.9 is BackingMmap; pass WithBacking(BackingPread) on the rare filesystem that doesn't support mmap or when you need os.File truncation semantics.

Has no effect on Open (which already takes a caller-provided io.ReaderAt); only the path-resolving OpenFile honors this.

When set to BackingMmap and the underlying mmap call fails (FUSE mount that doesn't support mapping, etc.), OpenFile returns ErrMmapUnavailable wrapping the underlying error rather than silently falling back. Callers that want auto-fallback should retry with WithBacking(BackingPread).

func WithCorruptTilePolicy

func WithCorruptTilePolicy(p CorruptTilePolicy) Option

WithCorruptTilePolicy sets the behavior for corrupt-edge tiles. v0.1 supports only CorruptTileError.

func WithMemoryBudget added in v0.30.0

func WithMemoryBudget(bytes int64) Option

WithMemoryBudget sets the per-Slide live-memory budget (bytes) for the ScaledStrips read path. Governs the decoded-tile cache so peak memory stays flat regardless of slide width / DZI tile size. Default 1 GiB; also settable via OPENTILE_READ_MEMORY_BUDGET (option wins). Values < 1 are ignored (default used).

func WithNDPISynthesizedLabel

func WithNDPISynthesizedLabel(enable bool) Option

WithNDPISynthesizedLabel controls whether NDPI Tiler.AssociatedImages() includes a synthesized "label" image, which Go produces by cropping the left 30% of the overview page. Python opentile 0.20.0 does not expose NDPI labels; this is a Go-side extension. Default: true (matches v0.2 behavior).

func WithTileSize

func WithTileSize(w, h int) Option

WithTileSize requests output tile dimensions in pixels. If unset, the format default is used (SVS: native tile size from the TIFF). Required for formats that have no native rectangular tiles (NDPI, v0.2+).

type OverlapMode added in v0.60.0

type OverlapMode int

OverlapMode classifies how a level's stored/decoded tiles relate to its content grid.

const (
	// OverlapNone is the clean-partition mode: tiles are a clean partition of Size. Grid tiles Size;
	// per-tile reads are verbatim content cells; verbatim tile-copy is safe.
	OverlapNone OverlapMode = iota

	// OverlapBordered is the padded-tile mode: stored/decoded tiles carry a redundant overlap border
	// (DZI/SZI Overlap>0). Grid STILL tiles Size (content cells partition it);
	// crop each decoded tile to TileContentRect, or use the region API.
	OverlapBordered

	// OverlapStitched is the compacted-grid mode: the stitch layout compacted the grid (BIF). Grid does
	// NOT tile Size (Grid.W×TileSize.W > Size.W); per-tile reads are raw
	// overlapping frames at stored positions; use the region API.
	OverlapStitched
)

func (OverlapMode) String added in v0.60.0

func (m OverlapMode) String() string

String returns a lowercase label ("none" / "bordered" / "stitched").

type Point

type Point struct {
	X, Y int
}

Point is a 2D integer position measured in pixels or tile units.

func (Point) String

func (p Point) String() string

type Pyramid added in v0.41.0

type Pyramid struct {
	// Name identifies this pyramid. For OME-TIFF, the <Image Name="...">
	// attribute. Empty for single-image formats.
	Name string

	// Index is the 0-based document-order index of this Pyramid within
	// the parent Slide. Obtain a *Pyramid via s.Pyramid(i) or s.Pyramids().
	Index int

	// Levels is the pyramid for this image, finest-to-coarsest. Level 0
	// is the full-resolution base; subsequent indices are progressively
	// downsampled.
	Levels []Level
	// contains filtered or unexported fields
}

Pyramid identifies one multi-resolution image within a slide. Single-image formats carry a single Pyramid. OME-TIFF can carry multiple.

func (*Pyramid) BestLevelForDownsample added in v0.41.0

func (p *Pyramid) BestLevelForDownsample(downsample float64) *Level

BestLevelForDownsample returns the *Level whose Downsample factor is the largest value ≤ the requested downsample (openslide semantics). Returns level 0 when every level is finer than requested.

func (*Pyramid) Level added in v0.41.0

func (p *Pyramid) Level(i int) (*Level, error)

Level returns the i-th level of this pyramid, or ErrLevelOutOfRange if i is out of range.

func (*Pyramid) ReadRegionScaled added in v0.41.0

func (p *Pyramid) ReadRegionScaled(src Region, out Size, opts ...DecodeOption) (*decoder.Image, error)

ReadRegionScaled reads an L0-coord rectangle within this pyramid and resamples it to out. See (*Slide).ReadRegionScaled for semantics.

func (*Pyramid) ReadRegionScaledInto added in v0.41.0

func (p *Pyramid) ReadRegionScaledInto(src Region, dst *decoder.Image, opts ...DecodeOption) error

ReadRegionScaledInto fills the caller-provided dst with the resampled L0-coord rectangle within this pyramid.

func (*Pyramid) RenderThumbnail added in v0.47.0

func (p *Pyramid) RenderThumbnail(bounds Size, opts ...DecodeOption) (*decoder.Image, error)

RenderThumbnail renders the whole slide (this pyramid) downscaled to fit bounds, preserving aspect ratio, as a freshly-resampled image. A zero (or negative) value on either axis of bounds is unconstrained — the output size is derived from the other axis and the slide's aspect ratio:

bounds {W:256, H:256} → largest image fitting inside 256×256 (fit-box)
bounds {W:256, H:0}   → width 256, height from aspect (fit-width)
bounds {W:0,   H:256} → height 256, width from aspect (fit-height)

It never upscales beyond level 0 (if bounds exceeds L0 the output is L0's extent). The thumbnail is RENDERED from the image pyramid (best-level-sourced and Lanczos-resampled via ReadRegionScaled, so memory stays bounded for large slides) — it is NOT the embedded AssociatedThumbnail / AssociatedOverview; use AssociatedImages() for those. For BIF the render is correctly stitched.

Returns an error if bounds constrains neither axis, if level 0 is unavailable, or (like ReadRegionScaled) if no decoder is registered for level 0's compression. opts pass through to the underlying decode (e.g. WithFormat).

func (*Pyramid) ScaledStrips added in v0.41.0

func (p *Pyramid) ScaledStrips(src Region, out Size, stripHeight int, opts ...StripOption) *StripIterator

ScaledStrips returns a scaled-strip iterator over this pyramid's L0 rectangle. See (*Slide).ScaledStrips for the iteration API; the caller must Close the returned iterator.

type Rational added in v0.31.0

type Rational struct{ Num, Denom uint32 }

Rational is an unsigned TIFF RATIONAL value.

type Region

type Region struct {
	Origin Point
	Size   Size
}

Region is an axis-aligned rectangle in pixel or tile units.

func (Region) Contains

func (r Region) Contains(p Point) bool

Contains reports whether p lies inside r (inclusive of origin, exclusive of the far edge).

type Report added in v0.45.0

type Report struct {
	Format   Format // detected format; FormatUnknown when Unopenable
	Findings []Finding
}

Report is the result of validating one file.

func Validate added in v0.45.0

func Validate(r io.ReaderAt, size int64, opts ...ValidateOption) (*Report, error)

Validate validates an in-memory / streamed source of the given size (tiers 0 + 1). Operational error semantics match ValidateFile.

func ValidateFile added in v0.45.0

func ValidateFile(path string, opts ...ValidateOption) (*Report, error)

ValidateFile opens path and validates it (tiers 0 + 1). The returned error is operational only (path missing / unreadable); a file that fails to open or is structurally broken yields a *Report whose findings describe the problem.

We stat first so a genuinely absent/unreadable path is an operational error, while a path that exists but fails to open/parse becomes a CheckUnopenable finding. OpenFile handles both the single-file and DICOM series-directory cases.

func (*Report) OK added in v0.45.0

func (r *Report) OK() bool

OK reports whether the file is well-formed per opentile-go's reader: true iff there are no Error-severity findings. Warning/Info do not affect OK.

func (*Report) Worst added in v0.45.0

func (r *Report) Worst() Severity

Worst returns the highest severity present, or Info for an empty report.

type Severity added in v0.45.0

type Severity int

Severity ranks a validation Finding.

const (
	// Info is a legal-but-unusual observation (e.g. an orphan IFD).
	Info Severity = iota
	// Warning is unusual and possibly wrong, but not provably broken.
	Warning
	// Error is a structural defect: the file is not well-formed per
	// opentile-go's reader.
	Error
)

func (Severity) String added in v0.45.0

func (s Severity) String() string

String renders a Severity for human output.

type Size

type Size struct {
	W, H int
}

Size is a 2D integer extent measured in pixels or tile units.

func (Size) Area

func (s Size) Area() int

func (Size) String

func (s Size) String() string

type Slide added in v0.23.0

type Slide struct {
	// contains filtered or unexported fields
}

Slide is the canonical handle for an open whole-slide image. Constructed via OpenFile (path) or Open (io.ReaderAt). Replaces the pre-v0.23 Tiler interface as the public return type of Open and OpenFile.

Concurrency contract: all accessor methods (Format, Pyramids, Levels, Level, AssociatedImages, Metadata, ICCProfile) are safe to call concurrently. Tile reads via *Level / *Pyramid methods are safe concurrently. Close must not race with in-flight tile reads.

func Open

func Open(r io.ReaderAt, size int64, opts ...Option) (*Slide, error)

Open parses r as a WSI file and returns a *Slide for the matching format. size is the total file size in bytes.

Dispatch probes each registered format in registration order; the first whose match function returns nil wins. Returns an error if no format claims the input (requires a format package to be imported, e.g. _ "github.com/wsilabs/opentile-go/formats/all").

func OpenFile

func OpenFile(path string, opts ...Option) (*Slide, error)

OpenFile opens path for reading and delegates to Open. The returned *Slide owns the underlying file handle (or memory map); Close releases it.

DICOM series (Contract 1 & 2)

DICOM VL Whole Slide Microscopy is the only format reachable via OpenFile but NOT via Open(io.ReaderAt, size). A DICOM series is multi-file; Open cannot express it. When the formats/dicom package is imported (e.g. via _ "github.com/wsilabs/opentile-go/formats/all"), OpenFile detects DICOM before the normal single-file dispatch:

  • Directory path: opens all WSM .dcm files in the directory.
  • Single .dcm path (Contract 2): performs a bounded sibling-scan — same directory only, same SeriesUID only, WSM-filtered — so that passing any one instance opens the full series.

The WithBacking option is accepted but ignored for DICOM (the Tiler owns its own per-instance mmaps).

Default backing since v0.9 is BackingMmap: the file is memory-mapped read-only and tile reads become userspace memcpys from the mapped region — no pread(2) syscall per Level.Tile call. The kernel page cache handles paging in tile-data regions on first access; warm-cache reads hit RAM at memory-bandwidth speed.

Pass WithBacking(BackingPread) to opt out and use the v0.8 (and earlier) os.File + pread path. Required for filesystems that don't support mmap (some FUSE / network mounts) or when the caller specifically needs os.File truncation semantics.

Failure modes:

  • mmap unavailable for this file (filesystem doesn't support it, or some platform-specific failure): returns ErrMmapUnavailable wrapping the underlying error. Callers wanting automatic fallback should retry with WithBacking(BackingPread).
  • file truncated underneath an open mmap-backed *Slide: subsequent Tile() calls into the truncated region raise SIGBUS in the calling thread. WSI files don't get truncated under normal use; if your storage allows it, use BackingPread.

func (*Slide) AssociatedImages added in v0.41.0

func (s *Slide) AssociatedImages() []AssociatedImage

AssociatedImages returns the auxiliary images (label, macro, thumbnail, overview, ...) embedded in this slide.

func (*Slide) Close added in v0.23.0

func (s *Slide) Close() error

Close releases resources held by the slide. Close releases the Slide's resources: drains every cached decoder pool, then delegates to the underlying reader (which closes the mmap or file handle and tears down format-specific state).

v0.27 contract: Close must not race with in-flight tile reads. v0.28 preserves that. A racing Borrow gets ErrClosed; a racing Decode completes against an already-borrowed Decoder, then Return closes it directly via the pool's closed-pool branch.

func (*Slide) Format added in v0.23.0

func (s *Slide) Format() Format

Format returns the canonical format identifier.

func (*Slide) ICCProfile added in v0.23.0

func (s *Slide) ICCProfile() []byte

ICCProfile returns the embedded color profile bytes, or nil if the slide has none.

func (*Slide) Level added in v0.23.0

func (s *Slide) Level(i int) (*Level, error)

Level is a shortcut for s.Pyramid(0).Level(i). Returns ErrLevelOutOfRange if i is out of range (or the slide carries no pyramids).

v1.0: returns a stable *Level into the navigation cache.

func (*Slide) Levels added in v0.23.0

func (s *Slide) Levels() []*Level

Levels is a shortcut for s.Pyramid(0).Levels(). Returns nil if the slide carries no pyramids.

v1.0: returns []*Level — stable pointers into the navigation cache.

func (*Slide) Metadata added in v0.23.0

func (s *Slide) Metadata() Metadata

Metadata returns the cross-format metadata view.

func (*Slide) Pyramid added in v0.41.0

func (s *Slide) Pyramid(i int) *Pyramid

Pyramid returns the i-th pyramid, or nil if i is out of range.

v1.0: returns a stable *Pyramid into the navigation cache.

func (*Slide) Pyramids added in v0.41.0

func (s *Slide) Pyramids() []*Pyramid

Pyramids returns the main pyramids carried by this file. Always returns at least one Pyramid; multi-image OME-TIFF exposes multiple. Index 0 is the legacy Levels() / Level(i) shortcut target.

v1.0: returns []*Pyramid — stable pointers into the Slide's internal navigation cache. The same *Pyramid is returned across calls (pointer identity is preserved), and each *Pyramid / *Level carries the receiver-method read API.

func (*Slide) RenderMacro added in v0.47.0

func (s *Slide) RenderMacro(bounds Size, opts ...DecodeOption) (*decoder.Image, error)

RenderMacro renders a synthesized "pseudo-macro": a slide-shaped canvas (the non-label scan area of a standard microscope slide, ~50×25 mm) with the whole-slide tissue thumbnail composited at its TRUE physical size — derived from the slide's microns-per-pixel — and centred. It gives a viewer a macro-style orientation image for slides that don't embed one.

`bounds` sizes the slide canvas (same zero-axis fit convention as RenderThumbnail: a zero axis is unconstrained). The scan area is ~2:1, so bounds {W:600} → a 600×300 canvas.

Physical scale comes from Metadata.MPP; if that's absent, it falls back to the objective magnification (mpp ≈ 10 / Magnification: 40× → 0.25, 20× → 0.5). If the slide reports neither MPP nor magnification, RenderMacro returns an error (it cannot place the tissue to scale).

The tissue is centred (true on-slide POSITION is not yet modelled — a future enhancement). If the tissue is physically larger than the scan area it is scaled down to fit, preserving aspect. For BIF the tissue render is correctly stitched. opts pass through to the tissue decode (e.g. WithFormat).

func (*Slide) RenderThumbnail added in v0.47.0

func (s *Slide) RenderThumbnail(bounds Size, opts ...DecodeOption) (*decoder.Image, error)

RenderThumbnail renders the whole slide downscaled to fit bounds, using the first pyramid. See (*Pyramid).RenderThumbnail for the sizing convention and semantics. For multi-pyramid files (e.g. some OME-TIFF), use s.Pyramid(i).RenderThumbnail to choose a specific pyramid.

func (*Slide) TIFFDirectories added in v0.41.0

func (s *Slide) TIFFDirectories() ([]TIFFDirectory, bool)

TIFFDirectories enumerates every TIFF IFD (including orphan IFDs not surfaced as a level or associated image). ok=false for non-TIFF formats (IFE, SZI). The escape hatch for "dump all"; prefer LevelTIFFTags / AssociatedImage.TIFFTags() for everyday access.

func (*Slide) UnwrapReader added in v0.23.0

func (s *Slide) UnwrapReader() any

UnwrapReader returns the underlying format-specific reader. Format packages use this to chain-walk through *Slide to their own concrete reader type (e.g., bif.MetadataOf(slide) walks the chain to find the BIF *Tiler).

func (*Slide) Validate added in v0.45.0

func (s *Slide) Validate(opts ...ValidateOption) *Report

Validate runs the Tier-1 structural checks on an already-open Slide. There is no Tier 0 (it already opened) and no operation can fail, so there is no error return. Reuses the Slide's parsed state.

type StripIterator added in v0.26.0

type StripIterator struct {
	// contains filtered or unexported fields
}

StripIterator yields horizontal strips of a slide scaled to a target output resolution. Not safe for concurrent use; one goroutine drives Next() / Close() per iterator.

func (*StripIterator) Close added in v0.26.0

func (it *StripIterator) Close() error

Close releases the iterator's workers + cache. Safe to call multiple times.

func (*StripIterator) Next added in v0.26.0

func (it *StripIterator) Next() (*decoder.Image, error)

Next returns the next decoded strip image. Returns io.EOF when all strips have been consumed, and io.ErrClosedPipe after Close.

func (*StripIterator) Strips added in v0.26.0

func (it *StripIterator) Strips() int

Strips returns the total number of strips this iterator will yield.

type StripOption added in v0.26.0

type StripOption func(*stripConfig)

StripOption configures a ScaledStrips iterator. See WithStripWorkers, WithStripLookahead, WithStripIDCTScale, WithStripKernel, WithStripContext.

func WithStripContext added in v0.26.0

func WithStripContext(ctx context.Context) StripOption

WithStripContext binds the iterator's worker pool to a cancellation context. Default: context.Background().

Cancelling ctx aborts in-flight Next() calls with ctx.Err(). Workers also respond to *StripIterator.Close().

func WithStripIDCTScale added in v0.26.0

func WithStripIDCTScale(scale int) StripOption

WithStripIDCTScale overrides the auto-selected codec-domain downscale factor. Valid: 1, 2, 4, 8. Default 0 = auto-select based on output downsample. Honored by scale-capable codecs (jpeg, jpeg2000, htj2k); other codecs ignore it (decode at full level resolution).

func WithStripKernel added in v0.26.0

func WithStripKernel(k resample.Kernel) StripOption

WithStripKernel sets the resample kernel applied after the source-tile decode step (when IDCT alone doesn't reach the target output dims). Default: resample.Lanczos.

func WithStripLookahead added in v0.26.0

func WithStripLookahead(strips int) StripOption

WithStripLookahead sets how many strips ahead the iterator pre-fetches source tiles for. Default: 2. 0 disables lookahead entirely (workers idle between Next() calls). Higher values trade memory for steady-state throughput on slow consumers.

func WithStripWorkers added in v0.26.0

func WithStripWorkers(n int) StripOption

WithStripWorkers sets the number of parallel source-tile decode workers. Default: runtime.NumCPU(). Values < 1 are clamped to 1.

type TIFFDirectory added in v0.31.0

type TIFFDirectory struct {
	Type           DirectoryType
	Image          int
	Level          int
	AssociatedType AssociatedType
	Tags           TIFFTags
}

TIFFDirectory is one IFD with structured identity. Image/Level are valid when Type==DirLevel; AssociatedType is the associated image Type() when Type==DirAssociated.

func (TIFFDirectory) Tag added in v0.31.0

func (d TIFFDirectory) Tag(number uint16) (TIFFTag, bool)

Tag is a convenience for d.Tags.Tag(number).

type TIFFTag added in v0.31.0

type TIFFTag struct {
	Number uint16
	Name   string
	Type   TIFFType
	Count  int
	Raw    []byte
	// contains filtered or unexported fields
}

TIFFTag is one parsed TIFF tag, typed. Number is always set (the key for vendor/private tags); Name is "" when not in the known-tag dictionary. Raw is the verbatim payload (file byte order) for faithful re-encode.

func (TIFFTag) ASCII added in v0.31.0

func (t TIFFTag) ASCII() (string, bool)

ASCII returns the string value, ok=false unless Type==TIFFASCII.

func (TIFFTag) Rationals added in v0.31.0

func (t TIFFTag) Rationals() ([]Rational, bool)

Rationals returns rational values, ok=false unless Type==TIFFRational.

func (TIFFTag) Uints added in v0.31.0

func (t TIFFTag) Uints() ([]uint64, bool)

Uints returns unsigned integer values, ok=false unless the type is an unsigned integer type.

type TIFFTags added in v0.31.0

type TIFFTags []TIFFTag

TIFFTags is the set of tags on one IFD with lookup helpers.

func TIFFTagsFromPage added in v0.31.0

func TIFFTagsFromPage(p *tiff.Page) TIFFTags

TIFFTagsFromPage builds the public TIFFTags for a parsed TIFF page. For use by format readers implementing the TIFF-tag provider; not part of the consumer-facing surface (the parameter type is internal).

func (TIFFTags) ByName added in v0.31.0

func (ts TIFFTags) ByName(name string) (TIFFTag, bool)

ByName returns the tag with the given dictionary name, ok=false if absent.

func (TIFFTags) Tag added in v0.31.0

func (ts TIFFTags) Tag(number uint16) (TIFFTag, bool)

Tag returns the tag with the given number, ok=false if absent.

type TIFFType added in v0.31.0

type TIFFType uint16

TIFFType mirrors the TIFF field type. Named so consumers can interpret TIFFTag.Type without a magic-number table.

const (
	TIFFByte      TIFFType = 1
	TIFFASCII     TIFFType = 2
	TIFFShort     TIFFType = 3
	TIFFLong      TIFFType = 4
	TIFFRational  TIFFType = 5
	TIFFUndefined TIFFType = 7
	TIFFSShort    TIFFType = 8
	TIFFSLong     TIFFType = 9
	TIFFSRational TIFFType = 10
	TIFFLong8     TIFFType = 16
)

type TileCoord

type TileCoord struct {
	X, Y int
	Z    int
	C    int
	T    int
}

TileCoord identifies a tile by its position in the multi- dimensional WSI space. X and Y are the existing 2D grid position; Z, C, and T select among focal planes (Z), fluorescence / spectral channels (C), and time points (T) respectively.

Z, C, T default to zero — a TileCoord literal {X: x, Y: y} addresses the same tile that Level.Tile(x, y) returns. Zero is the "nominal" / "first" / "T=0" plane in every dimension.

Valid ranges per axis:

0 <= X < Level.Grid().W
0 <= Y < Level.Grid().H
0 <= Z < Image.SizeZ()
0 <= C < Image.SizeC()
0 <= T < Image.SizeT()

Out-of-range values yield *TileError wrapping ErrDimensionUnavailable (axis is unsupported on this Image — SizeZ/C/T == 1) or ErrTileOutOfBounds (axis exists but the index is past its declared size).

Added in v0.7 alongside Level.TileAt and Image.SizeZ/SizeC/SizeT.

func (TileCoord) String

func (t TileCoord) String() string

type TileError

type TileError struct {
	Level int
	X, Y  int
	Err   error
}

TileError wraps a per-tile failure with the (level, x, y) that produced it. Consumers use errors.As to extract the coordinates and errors.Is against the exported sentinels to branch on the underlying cause.

func (*TileError) Error

func (e *TileError) Error() string

func (*TileError) Unwrap

func (e *TileError) Unwrap() error

type TileResult

type TileResult struct {
	Bytes []byte
	Err   error
}

TileResult carries the yield from RangeTiles.

type ValidateOption added in v0.45.0

type ValidateOption func(*validateConfig)

ValidateOption is the additive seam for future decode-based checks (Tier 2). v1 ships zero options.

type ValidationProbe added in v0.45.0

type ValidationProbe struct {
	// contains filtered or unexported fields
}

ValidationProbe is the collector handed to a reader's Validate hook. Readers call Flag once per problem occurrence; the engine rolls occurrences up by (Code, Pyramid, Level) into count-only Findings. Readers never count and never assign severity.

func (*ValidationProbe) Flag added in v0.45.0

func (p *ValidationProbe) Flag(code CheckCode, pyramid, level int, msg string)

Flag records one occurrence of a problem at the given locus. Use pyramid=-1 and/or level=-1 when the locus is the whole file or not applicable. The first occurrence's msg is kept as the Finding's Message; later occurrences only bump the Count.

func (*ValidationProbe) Size added in v0.45.0

func (p *ValidationProbe) Size() int64

Size is the backing file size in bytes (for byte-range bounds checks).

type Validator added in v0.45.0

type Validator interface {
	Validate(p *ValidationProbe)
}

Validator is implemented by format readers that contribute Tier-1 structural findings. The method is exported because readers live in other packages. A reader that does not implement it still gets the format-agnostic engine checks. Readers call ValidationProbe.Flag once per problem occurrence.

Directories

Path Synopsis
Package bench holds the shared benchmark fixture matrix and helpers used by both the Go-benchmark layer (bench/*_test.go) and the cross-language compare harness (cmd/bench/compare).
Package bench holds the shared benchmark fixture matrix and helpers used by both the Go-benchmark layer (bench/*_test.go) and the cross-language compare harness (cmd/bench/compare).
cmd
bench/compare command
Stub for the default (untagged) build so this package always has a buildable Go file — otherwise `go test ./...` / `make test` fail with "build constraints exclude all Go files".
Stub for the default (untagged) build so this package always has a buildable Go file — otherwise `go test ./...` / `make test` fail with "build constraints exclude all Go files".
bench/ndpi command
bench/ndpi-strips command
Command ndpi-strips drives the ScaledStrips DZI-descent path over an NDPI slide and snapshots an inuse_space heap profile at the HeapInuse peak.
Command ndpi-strips drives the ScaledStrips DZI-descent path over an NDPI slide and snapshots an inuse_space heap profile at the HeapInuse peak.
bench/svs command
ifefixheader command
Command ifefixheader rewrites the scale-relative resolution fields in an Iris File Extension (.iris) METADATA header so they are conformant with the file's own pyramid.
Command ifefixheader rewrites the scale-relative resolution fields in an Iris File Extension (.iris) METADATA header so they are conformant with the file's own pyramid.
Package decoder defines the public Decoder interface and registry for opentile-go's pluggable codec layer.
Package decoder defines the public Decoder interface and registry for opentile-go's pluggable codec layer.
all
Package all blank-imports every decoder subpackage so all codecs register at init() time.
Package all blank-imports every decoder subpackage so all codecs register at init() time.
avif
Package avif implements the AVIF decoder via libavif.
Package avif implements the AVIF decoder via libavif.
deflate
Package deflate implements the decoder for TIFF Compression=8 (Deflate/Zip).
Package deflate implements the decoder for TIFF Compression=8 (Deflate/Zip).
htj2k
Package htj2k implements the HTJ2K (High-Throughput JPEG 2000) decoder via OpenJPH (https://github.com/aous72/OpenJPH).
Package htj2k implements the HTJ2K (High-Throughput JPEG 2000) decoder via OpenJPH (https://github.com/aous72/OpenJPH).
jpeg
Package jpeg implements the JPEG decoder via libjpeg-turbo.
Package jpeg implements the JPEG decoder via libjpeg-turbo.
jpeg2000
Package jpeg2000 implements the JPEG 2000 decoder via openjp2.
Package jpeg2000 implements the JPEG 2000 decoder via openjp2.
jpegxl
Package jpegxl implements the JPEG-XL decoder via libjxl.
Package jpegxl implements the JPEG-XL decoder via libjxl.
lzw
Package lzw implements the decoder for TIFF Compression=5 (LZW).
Package lzw implements the decoder for TIFF Compression=5 (LZW).
none
Package none implements the trivial "no-compression" decoder for TIFF Compression=1 tiles, where the on-disk bytes ARE the decoded pixels.
Package none implements the trivial "no-compression" decoder for TIFF Compression=1 tiles, where the on-disk bytes ARE the decoded pixels.
webp
Package webp implements the WebP decoder via libwebp.
Package webp implements the WebP decoder via libwebp.
formats
all
Package all registers every format implemented by opentile-go.
Package all registers every format implemented by opentile-go.
bif
Package bif implements opentile-go format support for Ventana BIF (BioImagene Image File) — a BigTIFF dialect produced by Roche's VENTANA DP scanner family (DP 200, DP 600) and predecessor iScan scanners (Coreo, HT).
Package bif implements opentile-go format support for Ventana BIF (BioImagene Image File) — a BigTIFF dialect produced by Roche's VENTANA DP scanner family (DP 200, DP 600) and predecessor iScan scanners (Coreo, HT).
cogwsi
Package cogwsi reads Cloud Optimized GeoTIFF for WSI (COG-WSI) files — a strict COG extension produced by the wsitools transcoder (cornish/wsitools).
Package cogwsi reads Cloud Optimized GeoTIFF for WSI (COG-WSI) files — a strict COG extension produced by the wsitools transcoder (cornish/wsitools).
dzi
Package dzi reads bare Deep Zoom Image (DZI) slides: a filesystem .dzi XML manifest plus a sibling <name>_files/<level>/<col>_<row>.<ext> tile tree (the OpenSeadragon / Microsoft Deep Zoom layout).
Package dzi reads bare Deep Zoom Image (DZI) slides: a filesystem .dzi XML manifest plus a sibling <name>_files/<level>/<col>_<row>.<ext> tile tree (the OpenSeadragon / Microsoft Deep Zoom layout).
generictiff
Package generictiff implements opentile-go format support for generic tiled pyramidal TIFF — the catch-all reader for tiled WSI TIFFs without vendor metadata.
Package generictiff implements opentile-go format support for generic tiled pyramidal TIFF — the catch-all reader for tiled WSI TIFFs without vendor metadata.
ife
Package ife implements opentile-go format support for Iris File Extension (IFE) v1.0 — the IrisDigitalPathology bleeding-edge non-TIFF WSI container.
Package ife implements opentile-go format support for Iris File Extension (IFE) v1.0 — the IrisDigitalPathology bleeding-edge non-TIFF WSI container.
leicascn
Package leicascn implements opentile-go format support for Leica SCN — a BigTIFF dialect produced by Leica SCN400 / SCN400F scanners (production discontinued ~2015).
Package leicascn implements opentile-go format support for Leica SCN — a BigTIFF dialect produced by Leica SCN400 / SCN400F scanners (production discontinued ~2015).
ndpi
Package ndpi implements opentile-go format support for Hamamatsu NDPI files.
Package ndpi implements opentile-go format support for Hamamatsu NDPI files.
ometiff
Package ometiff implements opentile-go format support for OME TIFF files — a TIFF dialect carrying OME-XML metadata in the first page's ImageDescription, with reduced-resolution pyramid levels stored as TIFF SubIFDs of the base page.
Package ometiff implements opentile-go format support for OME TIFF files — a TIFF dialect carrying OME-XML metadata in the first page's ImageDescription, with reduced-resolution pyramid levels stored as TIFF SubIFDs of the base page.
philipstiff
Package philipstiff reads tiles from Philips IntelliSite Pathology Solution TIFF whole-slide images.
Package philipstiff reads tiles from Philips IntelliSite Pathology Solution TIFF whole-slide images.
svs
Package svs implements opentile-go format support for Aperio SVS files.
Package svs implements opentile-go format support for Aperio SVS files.
szi
Package szi reads Smart Zoom Image (.szi) files — ZIP-wrapped Microsoft Deep Zoom pyramids with scan-properties.xml and an associated_images/ folder.
Package szi reads Smart Zoom Image (.szi) files — ZIP-wrapped Microsoft Deep Zoom pyramids with scan-properties.xml and an associated_images/ folder.
internal
assocdecode
Package assocdecode is a thin shared helper for decoding image-codec associated images through the decoder registry, so each format's AssociatedImage.Decode doesn't duplicate the registry plumbing.
Package assocdecode is a thin shared helper for decoding image-codec associated images through the decoder registry, so each format's AssociatedImage.Decode doesn't duplicate the registry plumbing.
bifxml
Package bifxml parses the XMP metadata embedded in Ventana BIF TIFF IFDs.
Package bifxml parses the XMP metadata embedded in Ventana BIF TIFF IFDs.
boxhalve
Package boxhalve finishes a partial codec resolution reduction by box- averaging the residual power-of-two factor, so a wavelet decoder that could only reduce part of the requested Scale still lands on exact dims.
Package boxhalve finishes a partial codec resolution reduction by box- averaging the residual power-of-two factor, so a wavelet decoder that could only reduce part of the requested Scale still lands on exact dims.
cog
Package cog parses the GDAL Cloud Optimized GeoTIFF ghost-area (the contiguous block of ASCII key-value metadata immediately following the TIFF header).
Package cog parses the GDAL Cloud Optimized GeoTIFF ghost-area (the contiguous block of ASCII key-value metadata immediately following the TIFF header).
decoderhandle
Package decoderhandle provides a small fixed-size pool of long-lived decoder.Decoder instances.
Package decoderhandle provides a small fixed-size pool of long-lived decoder.Decoder instances.
dicom
Package dicom parses the metadata of DICOM VL Whole Slide Microscopy (WSM) SOP instances for the formats/dicom reader.
Package dicom parses the metadata of DICOM VL Whole Slide Microscopy (WSM) SOP instances for the formats/dicom reader.
dzi
Package dzi parses the Microsoft Deep Zoom Image (DZI) manifest XML format and computes per-level / per-tile coordinate information.
Package dzi parses the Microsoft Deep Zoom Image (DZI) manifest XML format and computes per-level / per-tile coordinate information.
fastpath
Package fastpath holds dispatch sentinel errors shared between the opentile root and format-specific readers.
Package fastpath holds dispatch sentinel errors shared between the opentile root and format-specific readers.
format
Package format defines the internal Reader interface every opentile-go format implementation provides.
Package format defines the internal Reader interface every opentile-go format implementation provides.
j2kheader
Package j2kheader is a pure-Go, header-only parser for JPEG 2000 family codestreams (J2K Part 1 and HTJ2K Part 15, raw or JP2/JPH-boxed).
Package j2kheader is a pure-Go, header-only parser for JPEG 2000 family codestreams (J2K Part 1 and HTJ2K Part 15, raw or JP2/JPH-boxed).
jpeg
Package jpeg provides marker-level JPEG bitstream manipulation sufficient to assemble valid JPEGs from TIFF-embedded scan fragments.
Package jpeg provides marker-level JPEG bitstream manipulation sufficient to assemble valid JPEGs from TIFF-embedded scan fragments.
jpegturbo
Package jpegturbo provides a minimal cgo wrapper over libjpeg-turbo's tjTransform operation, scoped to the lossless MCU-aligned JPEG crop that opentile-go needs for one-frame NDPI pyramid levels and NDPI label cropping.
Package jpegturbo provides a minimal cgo wrapper over libjpeg-turbo's tjTransform operation, scoped to the lossless MCU-aligned JPEG crop that opentile-go needs for one-frame NDPI pyramid levels and NDPI label cropping.
oneframe
Package oneframe provides shared infrastructure for reading "single big JPEG, virtualised into tile cells" pyramid pages — used by NDPI's non-tiled levels (formats/ndpi/oneframe.go pre-v0.6) and OME-TIFF's reduced-resolution levels (formats/ometiff/oneframe.go in v0.6).
Package oneframe provides shared infrastructure for reading "single big JPEG, virtualised into tile cells" pyramid pages — used by NDPI's non-tiled levels (formats/ndpi/oneframe.go pre-v0.6) and OME-TIFF's reduced-resolution levels (formats/ometiff/oneframe.go in v0.6).
openslideshim
Package openslideshim is a minimal cgo wrapper over libopenslide, used ONLY by the benchmark suite to compare opentile-go against openslide.
Package openslideshim is a minimal cgo wrapper over libopenslide, used ONLY by the benchmark suite to compare opentile-go against openslide.
tiff
Package tiff parses a minimal subset of the TIFF file format sufficient to locate compressed tile byte ranges for whole-slide imaging TIFFs.
Package tiff parses a minimal subset of the TIFF file format sufficient to locate compressed tile byte ranges for whole-slide imaging TIFFs.
tifflzw
Package tifflzw implements the Lempel-Ziv-Welch compressed data format as used by the TIFF file format, including the "off by one" code-width transition that makes TIFF LZW incompatible with stdlib compress/lzw.
Package tifflzw implements the Lempel-Ziv-Welch compressed data format as used by the TIFF file format, including the "off by one" code-width transition that makes TIFF LZW incompatible with stdlib compress/lzw.
tiffstrip
Package tiffstrip decodes strip-based (non-image-codec) TIFF associated images — uncompressed, LZW, or Deflate, with optional horizontal differencing (Predictor=2) — into faithful decoder.Image RGB(A) pixels.
Package tiffstrip decodes strip-based (non-image-codec) TIFF associated images — uncompressed, LZW, or Deflate, with optional horizontal differencing (Predictor=2) — into faithful decoder.Image RGB(A) pixels.
tiffvalidate
Package tiffvalidate provides structural validation helpers shared by the TIFF-based format readers: byte-range bounds for tile/strip data and orphan-IFD detection.
Package tiffvalidate provides structural validation helpers shared by the TIFF-based format readers: byte-range bounds for tile/strip data and orphan-IFD detection.
opentile
opentiletest
Package opentiletest provides test helpers for opentile consumers and the library's own internal tests.
Package opentiletest provides test helpers for opentile consumers and the library's own internal tests.
Package resample provides pure-Go pixel resamplers operating on decoder.Image.
Package resample provides pure-Go pixel resamplers operating on decoder.Image.
Package tests contains integration test helpers and fixture schemas shared between integration and fixture-generation tests.
Package tests contains integration test helpers and fixture schemas shared between integration and fixture-generation tests.
download command
download fetches openslide's public test slides into OPENTILE_TESTDIR.
download fetches openslide's public test slides into OPENTILE_TESTDIR.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL