decoder

package
v0.53.0 Latest Latest
Warning

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

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

Documentation

Overview

Package decoder defines the public Decoder interface and registry for opentile-go's pluggable codec layer. Codec-specific subpackages (decoder/jpeg, decoder/jpeg2000, decoder/lzw, etc.) register themselves into this package's registry at init() time.

Most consumers wanting "all codecs available" should blank-import the decoder/all subpackage:

import _ "github.com/wsilabs/opentile-go/decoder/all"

Smaller-footprint consumers can blank-import only the codec subpackages they need.

The decoder layer backs the Level / Pyramid read methods (DecodedTile / ReadRegion / ReadRegionScaled / ScaledStrips). It is also usable standalone for third-party Go pathology code that wants decoded tile bytes from opentile-go-readable WSI files.

Design spec: docs/superpowers/specs/2026-05-23-opentile-go-v22-decoder-resample-lift-design.md.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrCodecUnavailable is returned by the stub Decoder of a codec
	// subpackage that was excluded from this build (via -tags
	// no<codec> or -tags nocgo). The wrapping error message names the
	// codec and the build tag to remove.
	ErrCodecUnavailable = errors.New("decoder: codec not available in this build")

	// ErrUnsupportedScale is returned by Decode when DecodeOptions.Scale
	// is not a value the decoder supports. JPEG decoders accept 1, 2,
	// 4, 8; other decoders accept only 1.
	ErrUnsupportedScale = errors.New("decoder: scale factor not supported by this codec")

	// ErrUnsupportedFormat is returned by Decode when DecodeOptions.Format
	// is not producible by the decoder.
	ErrUnsupportedFormat = errors.New("decoder: pixel format not supported by this codec")

	// ErrDestinationSize is returned by Decode when DecodeOptions.Dst
	// is non-nil but its dimensions don't match the decoded size.
	ErrDestinationSize = errors.New("decoder: dst Image dimensions don't match decoded size")

	// ErrCorruptInput is returned by Decode when the compressed bytes
	// can't be parsed.
	ErrCorruptInput = errors.New("decoder: corrupt input data")
)

Sentinel errors used by Decode implementations. Wrap with fmt.Errorf("...: %w", ErrXxx) for codec-specific context; callers detect via errors.Is.

Functions

func Register

func Register(f Factory)

Register adds a factory to the global decoder registry. Called from each codec subpackage's init(). Last-in-wins on name or tag collision (intentional — lets consumers shadow a default decoder with a custom impl).

func Registered

func Registered() []string

Registered returns the canonical names of every registered decoder. Order is unspecified.

Types

type ChromaSubsampling added in v0.43.0

type ChromaSubsampling uint8

ChromaSubsampling is the chroma subsampling of a codestream's samples, expressed in the conventional J:a:b notation. SubsamplingNone is a single-channel (grayscale) codestream with no chroma to subsample.

const (
	SubsamplingUnknown ChromaSubsampling = iota
	SubsamplingNone                      // grayscale / no chroma channels
	Subsampling444                       // no chroma subsampling
	Subsampling422                       // 2:1 horizontal
	Subsampling420                       // 2:1 horizontal + vertical
	Subsampling440                       // 2:1 vertical
	Subsampling411                       // 4:1 horizontal
)

func (ChromaSubsampling) String added in v0.43.0

func (s ChromaSubsampling) String() string

type CodestreamInfo added in v0.42.0

type CodestreamInfo struct {
	// Components is the sample/channel count (1 = grayscale, 3 = color,
	// 4 = e.g. CMYK or color+alpha).
	Components int

	// BitDepth is the bits per component (typically 8; J2K/JXL may be higher).
	BitDepth int

	// Lossless reports whether the codestream is reversible/lossless. It is a
	// tri-state because not every codec exposes a header-only reversibility
	// signal: JPEG 2000 / HTJ2K report it from the COD transform and JPEG
	// baseline is always lossy, but JPEG XL's JxlBasicInfo carries no lossless
	// flag, so JXL reports LosslessUnknown.
	Lossless Lossless

	// ColorEncoding is the codec-domain color encoding of the samples.
	ColorEncoding ColorEncoding

	// ChromaSubsampling is the chroma subsampling of the samples. It matters to
	// frame-copy consumers that must distinguish, e.g., DICOM YBR_FULL_422
	// (4:2:2) from YBR_FULL (4:4:4) — a conformance distinction. JPEG reports it
	// from the SOF component sampling factors; JPEG 2000 / HTJ2K from the SIZ
	// per-component XRsiz/YRsiz. Grayscale codestreams report SubsamplingNone;
	// codecs that don't expose it (e.g. JPEG XL) report SubsamplingUnknown.
	ChromaSubsampling ChromaSubsampling

	// Boxed reports whether src is a boxed container (JP2 / JPH / JXL container)
	// rather than a raw codestream (J2K / raw JXL). Targets such as DICOM
	// require a specific encapsulated form (e.g. HTJ2K wants the raw .j2c
	// codestream, not the .jph box), so consumers need this before frame-copy.
	Boxed bool
}

CodestreamInfo is header-only metadata about an encoded tile/frame, obtained without a full decode (GH #41). It carries the codec-domain facts a consumer needs to frame-copy a tile verbatim into a target container (e.g. a DICOM TransferSyntax + PhotometricInterpretation) without re-decoding.

Mapping the codec-domain fields to a target container's vocabulary (e.g. DICOM PhotometricInterpretation) is the consumer's job; this struct is codec-domain only.

type CodestreamInspector added in v0.42.1

type CodestreamInspector interface {
	// Inspect parses src's codestream header and returns codec-domain metadata
	// without decoding the pixels. Returns ErrCorruptInput if the header can't
	// be parsed. Header-only is the contract: it must not decode the full frame.
	Inspect(src []byte) (CodestreamInfo, error)
}

CodestreamInspector is implemented by codec Factories that can return codec-domain metadata about an encoded codestream from its header alone — without fully decoding the frame (GH #41). Not every Factory implements it; consumers type-assert:

f, _ := decoder.GetByCompressionTag(tag)
if p, ok := f.(decoder.CodestreamInspector); ok {
	info, err := p.Inspect(compressed)
}

Implemented by jpeg, jpeg2000, htj2k, and jpegxl. Codecs without a meaningful codestream header (none / lzw / deflate / webp / avif) do not implement it, so the type assertion reports ok == false.

type ColorEncoding added in v0.42.0

type ColorEncoding uint8

ColorEncoding is the codec-domain color encoding of a codestream. The YBR_ICT / YBR_RCT values are the JPEG 2000 multiple-component transforms (irreversible / reversible); the String() forms match the DICOM PhotometricInterpretation spelling for convenience.

const (
	ColorUnknown   ColorEncoding = iota
	ColorGrayscale               // single luminance channel
	ColorRGB                     // RGB components, no decorrelating transform
	ColorYCbCr                   // JPEG (JFIF) luma/chroma
	ColorYBRICT                  // JPEG 2000 irreversible MCT (lossy)
	ColorYBRRCT                  // JPEG 2000 reversible MCT (lossless)
)

func (ColorEncoding) String added in v0.42.0

func (c ColorEncoding) String() string

type DecodeOptions

type DecodeOptions struct {
	// Scale is the in-codec downscale factor. Valid values: 1, 2, 4, 8;
	// other values return ErrUnsupportedScale. The zero value (0) is
	// treated as 1 (no scaling). Decode produces ceil(srcDim/Scale).
	// Supported by: jpeg (libjpeg IDCT fast-scale), jpeg2000 and htj2k
	// (DWT resolution-level decode, 1/2^log2(Scale), box-finishing any
	// residual when the codestream has too few levels). Other decoders
	// return ErrUnsupportedScale if Scale != 1.
	Scale int

	// Format is the requested output pixel format. Decoders return
	// ErrUnsupportedFormat if they can't produce the requested format.
	// Today: PixelFormatRGB and PixelFormatRGBA are universal.
	Format PixelFormat

	// Dst is an optional caller-supplied destination Image. If nil, the
	// decoder allocates. If non-nil and its dimensions match the
	// decoded size, the decoder writes into Dst.Pix and returns Dst.
	// Mismatched dimensions return ErrDestinationSize.
	Dst *Image
}

DecodeOptions configures a single Decode call. The zero value is valid (Scale=1, Format=PixelFormatRGB, Dst=nil → allocate fresh RGB).

type Decoder

type Decoder interface {
	// Decode the compressed bytes per opts. If opts.Dst is non-nil and
	// matches the decoded dimensions, writes into Dst and returns it;
	// otherwise allocates a fresh Image.
	Decode(compressed []byte, opts DecodeOptions) (*Image, error)

	// Close releases the decoder's internal state. Safe to call
	// multiple times. After Close, further Decode calls return an
	// error.
	Close() error
}

Decoder turns compressed tile bytes into a decoded Image. Decoders are NOT safe for concurrent use; callers running concurrent decodes on the same slide should construct one Decoder per goroutine via Factory.New().

type Factory

type Factory interface {
	// Name is the canonical codec identifier (e.g., "jpeg",
	// "jpeg2000", "lzw"). Lowercase.
	Name() string

	// TIFFCompressionTags lists the TIFF Compression tag values this
	// factory's decoder handles. Multiple tags allowed (e.g., JPEG
	// 2000 is both 33003 (Aperio) and 34712 (libtiff)). Empty for
	// non-TIFF-associated codecs.
	TIFFCompressionTags() []uint16

	// New returns a fresh Decoder instance. Each call returns a new
	// instance with its own state. Decoders are NOT safe for
	// concurrent use across goroutines.
	New() Decoder
}

Factory constructs decoders for a specific codec. Codec subpackages register a Factory in their init() function.

func Get

func Get(name string) (Factory, bool)

Get returns the factory registered for the given codec name, or (nil, false) if none is registered.

func GetByCompressionTag

func GetByCompressionTag(tag uint16) (Factory, bool)

GetByCompressionTag returns the factory registered for the given TIFF Compression tag value, or (nil, false) if none is registered.

type Image

type Image struct {
	Width, Height int
	Stride        int // bytes per row; may over-allocate for SIMD alignment
	Format        PixelFormat
	Pix           []byte // len(Pix) == Stride * Height
}

Image is a decoded raster bitmap.

func NewImage

func NewImage(w, h int) *Image

NewImage returns a freshly-allocated Image with PixelFormatRGB and Stride = w * 3. The Pix slice is zero-filled.

func NewImageFormat

func NewImageFormat(w, h int, fmt PixelFormat) *Image

NewImageFormat returns a freshly-allocated Image with the requested format. Stride is set to the format's bytes-per-pixel times w.

type Lossless added in v0.42.0

type Lossless uint8

Lossless is the tri-state reversibility of a codestream.

const (
	// LosslessUnknown means the codec exposes no header-only reversibility
	// signal (JPEG XL).
	LosslessUnknown Lossless = iota
	// LosslessYes means the codestream is reversible/lossless (J2K 5/3,
	// HTJ2K reversible).
	LosslessYes
	// LosslessNo means the codestream is lossy (J2K 9/7, JPEG baseline).
	LosslessNo
)

func (Lossless) String added in v0.42.0

func (l Lossless) String() string

type PixelFormat

type PixelFormat int

PixelFormat selects the in-memory pixel layout of a decoded Image.

const (
	// PixelFormatRGB is 3 bytes per pixel, no alpha channel.
	// The default — WSI imagery is opaque so alpha is wasted memory.
	PixelFormatRGB PixelFormat = iota

	// PixelFormatRGBA is 4 bytes per pixel with alpha = 0xFF.
	// Use when interop with Go stdlib image.NRGBA matters.
	PixelFormatRGBA
)

Directories

Path Synopsis
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.
Package avif implements the AVIF decoder via libavif.
Package avif implements the AVIF decoder via libavif.
Package deflate implements the decoder for TIFF Compression=8 (Deflate/Zip).
Package deflate implements the decoder for TIFF Compression=8 (Deflate/Zip).
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).
Package jpeg implements the JPEG decoder via libjpeg-turbo.
Package jpeg implements the JPEG decoder via libjpeg-turbo.
Package jpeg2000 implements the JPEG 2000 decoder via openjp2.
Package jpeg2000 implements the JPEG 2000 decoder via openjp2.
Package jpegxl implements the JPEG-XL decoder via libjxl.
Package jpegxl implements the JPEG-XL decoder via libjxl.
Package lzw implements the decoder for TIFF Compression=5 (LZW).
Package lzw implements the decoder for TIFF Compression=5 (LZW).
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.
Package webp implements the WebP decoder via libwebp.
Package webp implements the WebP decoder via libwebp.

Jump to

Keyboard shortcuts

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