jpeg2000

package module
v0.13.3 Latest Latest
Warning

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

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

README

jpeg2000

A fork of ajroetker/go-jpeg2000, under the same Apache-2.0 licence. It exists so that a fix can be used without waiting on an upstream that has not published since February. The import path is github.com/go-images/jpeg2000. Every change made here is stated in NOTICE, as Apache-2.0 section 4(b) requires.

What differs today: a four-component picture whose JP2 header declares the enumerated colour space CMYK decodes to an *image.CMYK instead of an *image.RGBA built from its first three components — which discarded the black plate. Measured against poppler on the reference picture: 255 levels of disagreement on every pixel became at most 2, over 2 440 044 samples.

Go

A pure Go JPEG2000 codec. Decode and encode JPEG2000 codestreams (.j2k/.j2c) and JP2 files (.jp2) with zero C dependencies.

Requirements

  • Go 1.25+

Installation

go get github.com/ajroetker/go-jpeg2000

Quick Start

Decoding
package main

import (
	"image/png"
	"log"
	"os"

	jpeg2000 "github.com/ajroetker/go-jpeg2000"
)

func main() {
	f, err := os.Open("input.jp2")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	img, err := jpeg2000.Decode(f)
	if err != nil {
		log.Fatal(err)
	}

	out, _ := os.Create("output.png")
	defer out.Close()
	png.Encode(out, img)
}
Encoding
package main

import (
	"image"
	"image/png"
	"log"
	"os"

	jpeg2000 "github.com/ajroetker/go-jpeg2000"
)

func main() {
	f, err := os.Open("input.png")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	img, _, err := image.Decode(f)
	if err != nil {
		log.Fatal(err)
	}

	out, _ := os.Create("output.j2k")
	defer out.Close()

	// Lossless encoding
	err = jpeg2000.Encode(out, img, &jpeg2000.EncodeOptions{
		Lossless: true,
	})
	if err != nil {
		log.Fatal(err)
	}
}
Automatic Format Detection
import (
	"image"
	_ "github.com/ajroetker/go-jpeg2000" // register format
)

img, format, err := image.Decode(reader) // format = "jpeg2000"

Features

Feature Status
Decode J2K codestreams Supported
Decode JP2 files Supported
Encode J2K codestreams Supported
Encode JP2 files Supported
5/3 reversible wavelet (lossless) Supported
9/7 irreversible wavelet (lossy) Supported
Multi-component color transform (RCT/ICT) Supported
EBCOT Tier-1 (MQ arithmetic coding) Supported
EBCOT Tier-2 (packet assembly) Supported
Rate control (PCRD-opt) Supported
Quality layers Supported
Grayscale and RGB images Supported
Multi-tile images Supported

Encode Options

type EncodeOptions struct {
	Lossless       bool      // true = 5/3 + RCT, false = 9/7 + ICT
	Quality        float64   // 0.0-1.0 (lossy only, default: 0.8)
	TargetSize     int       // target file size in bytes (overrides Quality)
	NumLayers      int       // quality layers (default: 1)
	TileWidth      int       // 0 = single tile
	TileHeight     int       // 0 = single tile
	NumResolutions int       // decomposition levels + 1 (default: 6)
	CodeBlockWidth int       // default: 64
	CodeBlockHeight int      // default: 64
	FileFormat     FileFormat // FormatJ2K or FormatJP2
}

Building

go build ./...
go test ./...
go test -bench=. -benchmem ./...

License

Apache 2.0

Documentation

Overview

Package jpeg2000 implements a pure Go JPEG2000 codec.

This package encodes and decodes JPEG2000 codestreams (.j2k/.j2c) and JP2 files (.jp2). It supports both lossless (5/3 reversible wavelet) and lossy (9/7 irreversible wavelet) compression modes.

Decoding:

img, err := jpeg2000.Decode(reader)
if err != nil {
    log.Fatal(err)
}

Encoding:

err := jpeg2000.Encode(writer, img, &jpeg2000.EncodeOptions{Lossless: true})
if err != nil {
    log.Fatal(err)
}

The package registers itself with the image package for automatic format detection:

import _ "github.com/ajroetker/go-jpeg2000"
img, _, err := image.Decode(reader)

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidMarker      = errors.New("jpeg2000: invalid marker")
	ErrUnsupportedFormat  = errors.New("jpeg2000: unsupported format")
	ErrInvalidHeader      = errors.New("jpeg2000: invalid header")
	ErrTruncatedData      = errors.New("jpeg2000: truncated data")
	ErrInvalidTile        = errors.New("jpeg2000: invalid tile")
	ErrTooManyTiles       = errors.New("jpeg2000: too many tiles")
	ErrImageTooLarge      = errors.New("jpeg2000: image dimensions exceed limit")
	ErrUnsupportedWavelet = errors.New("jpeg2000: unsupported wavelet filter")
	ErrUnsupportedQuant   = errors.New("jpeg2000: unsupported quantization")
	ErrDecodeFailed       = errors.New("jpeg2000: decode failed")
)

Functions

func Analyze2D_53

func Analyze2D_53(coeffs [][]int32, width, height, levels int)

Analyze2D_53 performs forward 2D 5/3 wavelet transform (lossless). Input: image samples in coeffs[y][x]. Output: subbands arranged as [LL, LH; HL, HH] per level. width, height: dimensions of the full image. levels: number of decomposition levels.

Per JPEG2000 standard (ITU-T T.800): forward transform applies vertical analysis first (columns), then horizontal analysis (rows). This is the opposite of the inverse transform which does horizontal then vertical.

func Analyze2D_53_At added in v0.13.0

func Analyze2D_53_At(coeffs [][]int32, tcx0, tcy0, tcx1, tcy1, levels int)

Analyze2D_53_At is the forward 5/3 transform of a tile-component that begins at (tcx0, tcy0) on the reference grid and ends before (tcx1, tcy1).

The POSITION is not decoration. Each lifting step alternates between even and odd samples, and which of the two a subband's first sample is depends on where the tile begins -- not on how wide it is. Synthesize2D_53_WithDims takes each resolution's X0/Y0 for exactly this, calling it cas; the forward transform used to assume every tile began at zero, so a tile that did not was analysed in one phase and synthesised in the other.

Analyze2D_53 keeps the old shape and passes an origin of zero, which is what an untiled picture and every existing caller have.

func Analyze2D_97

func Analyze2D_97(coeffs [][]float64, width, height, levels int)

Analyze2D_97 performs forward 2D 9/7 wavelet transform (lossy). Input: image samples in coeffs[y][x]. Output: subbands arranged as [LL, LH; HL, HH] per level. width, height: dimensions of the full image. levels: number of decomposition levels.

Per JPEG2000 standard (ITU-T T.800): forward transform applies vertical analysis first (columns), then horizontal analysis (rows). This is the opposite of the inverse transform which does horizontal then vertical.

func Analyze2D_97_At added in v0.13.0

func Analyze2D_97_At(coeffs [][]float64, tcx0, tcy0, tcx1, tcy1, levels int)

Analyze2D_97_At is Analyze2D_53_At's twin for the irreversible filter: the same reason, the same arithmetic, the other wavelet.

func ComputeLayerPasses

func ComputeLayerPasses(
	subbands []*EncoderSubband,
	numLayers int,
) []map[int]int

ComputeLayerPasses distributes coding passes across quality layers using a simple equal-pass distribution strategy. For more sophisticated rate-distortion optimization, the caller should compute passes per layer using the distortion values from EncodedPass.

This function assigns all passes of a code block to a single layer (layer 0). For multi-layer encoding, use rate-distortion optimization to determine optimal truncation points.

func ComputeLayerPassesRD

func ComputeLayerPassesRD(
	subbands []*EncoderSubband,
	numLayers int,
	targetRates []int,
) []map[int]int

ComputeLayerPassesRD distributes coding passes across quality layers using rate-distortion optimization. Passes are assigned to layers based on their distortion reduction per byte (slope), with higher-slope passes going to earlier layers.

targetRates[layer] specifies the target bytes for each layer (cumulative). A targetRate of 0 means include all remaining data.

Returns passesPerBlock[layer][blockIdx] = number of new passes for that layer.

func Decode

func Decode(r io.Reader) (image.Image, error)

Decode decodes a JPEG2000 image

func DecodeConfig

func DecodeConfig(r io.Reader) (image.Config, error)

DecodeConfig returns the image configuration without full decoding

func DecodeWithOptions

func DecodeWithOptions(r io.Reader, opts DecodeOptions) (image.Image, error)

DecodeWithOptions decodes a JPEG2000 image with progressive decoding options. This allows partial decoding for faster preview or reduced memory usage.

Example usage:

// Decode only first 2 quality layers at half resolution
img, err := DecodeWithOptions(r, DecodeOptions{MaxLayers: 2, Reduce: 1})

func DecodeWithUpsampling

func DecodeWithUpsampling(r io.Reader) (image.Image, error)

DecodeWithUpsampling decodes a JPEG2000 image with component upsampling. Components with XRsiz/YRsiz > 1 are upsampled to full image dimensions.

func Encode

func Encode(w io.Writer, img image.Image, opts *EncodeOptions) error

Encode encodes img as a JPEG2000 image and writes it to w.

func InitSubbandTagTrees

func InitSubbandTagTrees(sb *EncoderSubband)

InitSubbandTagTrees initializes the tag tree values for a subband. Must be called after all code blocks have been added and before the first call to EncodePacket. Sets inclusion values to each block's FirstLayer and ZBP values to each block's ZeroBitPlanes.

For rate-distortion optimized encoding, the caller should set FirstLayer on each EncoderCodeBlock before calling this function. For simple single-layer encoding, set FirstLayer = 0 for all blocks that have data.

func ResetEncoderCodeBlocks

func ResetEncoderCodeBlocks(subbands []*EncoderSubband)

ResetEncoderCodeBlocks resets the per-layer state of all code blocks in the provided subbands. This is useful when re-encoding with different layer assignments.

func ResetSubbandTagTreeStates

func ResetSubbandTagTreeStates(subbands []*EncoderSubband)

ResetSubbandTagTreeStates resets the tag tree encoding states for all provided subbands. This should be called when re-encoding packets (e.g., for rate-distortion optimization) to ensure consistent state. Node values are preserved; only the incremental encoding states are cleared.

func Synthesize2D_53

func Synthesize2D_53(coeffs [][]int32, width, height, levels int)

Synthesize2D_53 performs full 2D inverse 5/3 wavelet transform coeffs: coefficient array organized as [LL, LH; HL, HH] subbands per level JPEG2000 standard: forward is V→H (columns then rows), inverse is H→V (rows then columns) width, height: dimensions of the full image levels: number of decomposition levels

func Synthesize2D_53_WithDims

func Synthesize2D_53_WithDims(coeffs [][]int32, resDims []ResBounds)

Synthesize2D_53_WithDims performs 2D inverse 5/3 wavelet transform using explicit resolution dimensions instead of computing them. resDims[i] contains bounds for resolution level i (0=coarsest) The X0/Y0 values are used to compute DWT parity (cas) for tiles at odd positions.

func Synthesize2D_97

func Synthesize2D_97(coeffs [][]float32, width, height, levels int)

func Synthesize2D_97_WithDims

func Synthesize2D_97_WithDims(coeffs [][]float32, resDims []ResBounds)

Synthesize2D_97_WithDims performs 2D inverse 9/7 wavelet transform using explicit resolution dimensions instead of computing them. resDims[i] contains bounds for resolution level i (0=coarsest) The X0/Y0 values are used to compute DWT parity (cas) for tiles at odd positions.

func WriteJP2File

func WriteJP2File(w io.Writer, header *MainHeader, codestreamData []byte) error

WriteJP2File writes a complete JP2 file wrapping a JPEG2000 codestream. The JP2 file format (ITU-T T.800 Annex I) consists of a sequence of boxes:

  • Signature Box (jP): file identification
  • FileType Box (ftyp): brand and compatibility
  • JP2 Header Box (jp2h): image header and color specification
  • Contiguous Codestream Box (jp2c): the actual JPEG2000 codestream

Types

type CodeBlock

type CodeBlock struct {
	X, Y               int    // Position in subband
	Width, Height      int    // Dimensions
	Data               []byte // MQ-coded data
	NumPasses          int    // Number of coding passes
	ZeroBitPlanes      int    // Number of zero bit planes
	Lblock             int    // Log2 of block size indicator
	MagnitudeBitPlanes int    // Number of magnitude bit planes (Mb = GuardBits + Exp - 1)
	CodeBlockStyle     byte   // Codeblock coding style flags (from COD marker)
	SegmentLengths     []int  // Per-segment lengths (used when ERTERM is set for pass termination)
}

CodeBlock represents a code block within a subband

type CodeBlockInfo

type CodeBlockInfo struct {
	X, Y          int    // Position in subband's code block grid
	Width, Height int    // Actual dimensions
	ZeroBitPlanes int    // Number of leading zero bit planes
	TotalPasses   int    // Total coding passes received so far
	Data          []byte // Accumulated compressed data
	Lblock        int    // Length indicator exponent (starts at 3)
	IncludedLayer int    // First layer where included (-1 if not included)

	// Per-segment lengths when ERTERM or BYPASS mode is enabled.
	// For ERTERM: one entry per pass.
	// For BYPASS: one entry per segment (segments group passes by coding mode).
	SegmentLengths []int
	// contains filtered or unexported fields
}

CodeBlockInfo tracks decoding state of a code block

type CodestreamWriter

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

CodestreamWriter writes a JPEG2000 codestream to an io.Writer. It produces valid codestreams conforming to ITU-T T.800 by writing the required marker segments (SOC, SIZ, COD, QCD) and tile data.

func NewCodestreamWriter

func NewCodestreamWriter(w io.Writer, header *MainHeader) *CodestreamWriter

NewCodestreamWriter creates a new codestream writer that writes to w using the image parameters from header.

func (*CodestreamWriter) WriteEOC

func (cw *CodestreamWriter) WriteEOC() error

WriteEOC writes the end-of-codestream marker (EOC).

func (*CodestreamWriter) WriteMainHeader

func (cw *CodestreamWriter) WriteMainHeader() error

WriteMainHeader writes the main header of a JPEG2000 codestream. This includes the SOC marker followed by SIZ, COD, and QCD marker segments. Per ITU-T T.800, these must appear in this order before any tile-parts.

func (*CodestreamWriter) WriteTilePart

func (cw *CodestreamWriter) WriteTilePart(tileIdx int, tileData []byte) error

WriteTilePart writes a complete tile-part consisting of an SOT marker segment, the SOD marker, and the tile bitstream data. tileIdx is the zero-based tile index and tileData contains the pre-assembled packet data for this tile.

The tile-part length (Psot) in the SOT marker includes the SOT marker itself (2 bytes), the SOT segment (10 bytes), the SOD marker (2 bytes), and the tile data length.

type DecodeOptions

type DecodeOptions struct {
	// MaxLayers limits the number of quality layers to decode.
	// 0 means decode all layers (full quality).
	// Values 1+ decode only that many layers (lower = faster, lower quality).
	MaxLayers int

	// Reduce specifies the resolution reduction factor.
	// 0 means full resolution.
	// 1 means half resolution (skip finest decomposition level).
	// 2 means quarter resolution (skip two finest levels), etc.
	// The output image dimensions are divided by 2^Reduce.
	Reduce int
}

DecodeOptions controls progressive decoding behavior. This allows partial decoding for faster preview or reduced memory usage.

type Decoder

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

Decoder holds state for decoding a JPEG2000 image

type EncodeOptions

type EncodeOptions struct {
	// Lossless selects the compression mode:
	//   true  = 5/3 reversible wavelet + RCT (exact reconstruction)
	//   false = 9/7 irreversible wavelet + ICT (lossy)
	Lossless bool

	// Quality controls the compression ratio for lossy mode (0.0 to 1.0).
	// 1.0 = highest quality (lowest compression).
	// 0.5 = moderate quality.
	// 0.0 = lowest quality (highest compression).
	// Ignored when Lossless is true.
	Quality float64

	// TargetSize sets an explicit target file size in bytes.
	// If > 0, overrides Quality. 0 means use Quality instead.
	TargetSize int

	// NumLayers sets the number of quality layers (default: 1).
	NumLayers int

	// TileWidth and TileHeight set tile dimensions.
	// 0 means single tile (entire image).
	TileWidth  int
	TileHeight int

	// NumResolutions = NumDecompLevels + 1 (default: 6, meaning 5 decomposition levels).
	NumResolutions int

	// CodeBlockWidth and CodeBlockHeight (default: 64x64).
	// Must be powers of 2, max 64.
	CodeBlockWidth  int
	CodeBlockHeight int

	// Progression order (default: LRCP = 0).
	Progression byte

	// FileFormat selects J2K (raw codestream) or JP2 (with file format boxes).
	FileFormat FileFormat
}

EncodeOptions controls JPEG2000 encoding parameters.

type EncodedBlock

type EncodedBlock struct {
	// Per-pass encoded data
	Passes []EncodedPass

	// Number of significant (non-zero) bit planes
	NumBitPlanes int

	// Total number of coding passes
	NumPasses int

	// Zero bit planes (leading planes with no significant coefficients)
	ZeroBitPlanes int
}

EncodedBlock holds the result of EBCOT encoding a single code block.

type EncodedPass

type EncodedPass struct {
	Data       []byte  // MQ-encoded (or raw) bytes for this pass
	Length     int     // Length in bytes
	Type       int     // Pass type: 0=SPP, 1=MRP, 2=Cleanup
	BitPlane   int     // Which bit plane this pass encodes
	Distortion float64 // Distortion reduction from this pass (for rate control)
}

EncodedPass holds data for a single coding pass.

type EncoderCodeBlock

type EncoderCodeBlock struct {
	Block    *EncodedBlock
	SubbandX int // X position in subband's code block grid
	SubbandY int // Y position in subband's code block grid

	// Per-layer state tracking
	PassesIncluded int // Passes included in layers so far
	FirstLayer     int // First layer where included (-1 initially)

	// Lblock tracks the length indicator exponent for this code block.
	// Starts at 3 per ITU-T T.800. Incremented as needed to encode
	// pass lengths that exceed the current bit budget.
	Lblock int
}

EncoderCodeBlock holds a code block for encoding with its grid position.

func NewEncoderCodeBlock

func NewEncoderCodeBlock(block *EncodedBlock, subbandX, subbandY int) *EncoderCodeBlock

NewEncoderCodeBlock creates an EncoderCodeBlock with properly initialized state.

type EncoderResolution

type EncoderResolution struct {
	Level    int
	Subbands []*EncoderSubband
}

EncoderResolution holds subbands for encoding.

type EncoderSubband

type EncoderSubband struct {
	Type        SubbandType
	Width       int
	Height      int
	CodeBlocksX int
	CodeBlocksY int
	CodeBlocks  [][]*EncoderCodeBlock

	// Tag trees for this subband's precinct.
	// In the general case there is one pair of tag trees per precinct,
	// but for the common single-precinct case we store them directly here.
	InclusionTree *tagTree
	ZBPTree       *tagTree
}

EncoderSubband holds code blocks for encoding within a subband.

func NewEncoderSubband

func NewEncoderSubband(sbType SubbandType, width, height, codeBlocksX, codeBlocksY int) *EncoderSubband

NewEncoderSubband creates an EncoderSubband with initialized tag trees. All code blocks must be added to CodeBlocks before calling EncodePacket.

type FileFormat

type FileFormat int

FileFormat specifies the output file format.

const (
	FormatJ2K FileFormat = iota // Raw codestream (.j2k/.j2c)
	FormatJP2                   // JP2 file format with boxes (.jp2)
)

type JP2ChannelDef

type JP2ChannelDef struct {
	Channel     int // Channel number (Cn)
	Type        int // Channel type: 0=color, 1=opacity, 2=premult opacity, 0xFFFF=unspecified
	Association int // Color association: 1=R/Y, 2=G/Cb, 3=B/Cr, 0=whole image, 0xFFFF=unspecified
}

JP2ChannelDef holds channel definition box (cdef) data per ITU-T T.800 I.5.3.6

type JP2ColorMethod

type JP2ColorMethod uint8

JP2ColorMethod defines the color specification method

const (
	JP2ColorEnumerated JP2ColorMethod = 1 // Enumerated colorspace
	JP2ColorICC        JP2ColorMethod = 2 // Restricted ICC profile
	JP2ColorICCAny     JP2ColorMethod = 3 // Any ICC profile (JP2 extensions)
)

type JP2ColorSpace

type JP2ColorSpace uint32

JP2ColorSpace defines enumerated color spaces per ITU-T T.800 Table I.1

const (
	JP2ColorUnknown   JP2ColorSpace = 0
	JP2ColorBiLevel1  JP2ColorSpace = 1  // bi-level (1 = black)
	JP2ColorYCbCr1    JP2ColorSpace = 3  // YCbCr (ITU-R BT.601-5)
	JP2ColorYCbCr2    JP2ColorSpace = 4  // YCbCr (ITU-R BT.601-5 based on Rec.601)
	JP2ColorYCbCr3    JP2ColorSpace = 5  // YCbCr (ITU-R BT.709)
	JP2ColorPhotoYCC  JP2ColorSpace = 9  // PhotoYCC
	JP2ColorCMY       JP2ColorSpace = 11 // CMY
	JP2ColorCMYK      JP2ColorSpace = 12 // CMYK
	JP2ColorYCCK      JP2ColorSpace = 13 // YCCK
	JP2ColorCIELab    JP2ColorSpace = 14 // CIELab (default illuminant/range)
	JP2ColorBiLevel2  JP2ColorSpace = 15 // bi-level (1 = white)
	JP2ColorSRGB      JP2ColorSpace = 16 // sRGB
	JP2ColorGrayscale JP2ColorSpace = 17 // Greyscale
	JP2ColorSYCC      JP2ColorSpace = 18 // sYCC (standard YCbCr)
	JP2ColorCIEJab    JP2ColorSpace = 19 // CIEJab
	JP2ColorESRGB     JP2ColorSpace = 20 // e-sRGB
	JP2ColorROMM      JP2ColorSpace = 21 // ROMM-RGB
	JP2ColorYPbPr60   JP2ColorSpace = 22 // YPbPr (1125/60)
	JP2ColorYPbPr50   JP2ColorSpace = 23 // YPbPr (1250/50)
	JP2ColorESYCC     JP2ColorSpace = 24 // e-sYCC
)

type JP2ComponentMapping

type JP2ComponentMapping struct {
	Component   int // Codestream component index (CMP)
	MappingType int // 0=direct, 1=palette mapping (MTYP)
	PaletteCol  int // Palette column index (PCOL), only used if MappingType=1
}

JP2ComponentMapping holds component mapping box (cmap) data per ITU-T T.800 I.5.3.5

type JP2Metadata

type JP2Metadata struct {
	// From ihdr box
	Height      uint32
	Width       uint32
	NumComps    uint16
	BitDepth    int   // From BPC field (bit depth - 1, plus sign bit)
	Signed      bool  // Component sample signedness
	Compression uint8 // Should be 7 for JP2
	UnkC        uint8 // Colorspace unknown flag
	IPR         uint8 // Intellectual property flag

	// From colr box
	ColorMethod JP2ColorMethod
	Precedence  uint8
	Approx      uint8
	ColorSpace  JP2ColorSpace // Only valid if ColorMethod == JP2ColorEnumerated
	ICCProfile  []byte        // ICC profile data if ColorMethod == JP2ColorICC

	// From res box (optional)
	CaptureResX float64 // Capture resolution in grid points per meter
	CaptureResY float64
	DisplayResX float64 // Display resolution in grid points per meter
	DisplayResY float64

	// From pclr box (palette)
	Palette *JP2Palette

	// From cmap box (component mapping)
	ComponentMap []JP2ComponentMapping

	// From cdef box (channel definition)
	ChannelDefs []JP2ChannelDef

	// Metadata boxes (optional)
	UUIDData [][]byte // Raw UUID box contents
	XMLData  [][]byte // Raw XML box contents
	// contains filtered or unexported fields
}

JP2Metadata holds parsed JP2 container information

func (*JP2Metadata) GetChannelOrder

func (m *JP2Metadata) GetChannelOrder() []int

GetChannelOrder returns the output channel order based on cdef associations. Returns a mapping where result[outputIndex] = inputChannelIndex. For RGB output: association 1=R, 2=G, 3=B.

func (*JP2Metadata) IsGrayscale

func (m *JP2Metadata) IsGrayscale() bool

IsGrayscale returns true if the color space is grayscale

func (*JP2Metadata) IsSRGB

func (m *JP2Metadata) IsSRGB() bool

IsSRGB returns true if the color space is sRGB

func (*JP2Metadata) IsYCbCr

func (m *JP2Metadata) IsYCbCr() bool

IsYCbCr returns true if the color space is a YCbCr variant

func (*JP2Metadata) NeedsChannelReorder

func (m *JP2Metadata) NeedsChannelReorder() bool

NeedsChannelReorder returns true if cdef specifies a non-identity channel mapping for color channels (e.g., BGR instead of RGB).

type JP2Palette

type JP2Palette struct {
	NumEntries int     // Number of palette entries (NE)
	NumColumns int     // Number of columns/channels (NPC)
	BitDepths  []int   // Bit depth per column (Bi)
	Signed     []bool  // Whether each column is signed
	Entries    [][]int // [entry][column] lookup values
}

JP2Palette holds palette box (pclr) data per ITU-T T.800 I.5.3.4

type LayerAllocation

type LayerAllocation struct {
	// NumPasses[i] = number of passes for block i in this layer
	NumPasses []int
}

LayerAllocation specifies which passes of each block go into a quality layer.

type MainHeader

type MainHeader struct {
	// From SIZ marker
	Width      int    // Image width
	Height     int    // Image height
	XOsiz      int    // Horizontal offset
	YOsiz      int    // Vertical offset
	TileWidth  int    // Tile width
	TileHeight int    // Tile height
	XTOsiz     int    // Tile grid horizontal offset
	YTOsiz     int    // Tile grid vertical offset
	NumComps   int    // Number of components
	BitDepth   []int  // Bit depth per component
	Signed     []bool // Signed flag per component
	XRsiz      []int  // Horizontal sample separation
	YRsiz      []int  // Vertical sample separation

	// From COD marker
	ProgressionOrder byte // 0=LRCP, 1=RLCP, 2=RPCL, 3=PCRL, 4=CPRL
	NumLayers        int  // Number of quality layers
	MCT              bool // Multiple component transform used
	NumDecompLevels  int  // Number of decomposition levels
	CodeBlockWidth   int  // Code block width (power of 2)
	CodeBlockHeight  int  // Code block height (power of 2)
	CodeBlockStyle   byte // Code block coding style flags
	WaveletFilter    WaveletType
	UsesSOP          bool // SOP (Start of Packet) markers present
	UsesEPH          bool // EPH (End of Packet Header) markers present

	// Precinct sizes per resolution level (index 0 = resolution 0, lowest)
	// Each entry is [width_exponent, height_exponent] where size = 2^exponent
	// If nil, default precinct size (15,15) = 32768x32768 (effectively whole tile)
	PrecinctSizes [][2]int

	// From QCD marker (default quantization for all components)
	QuantStyle         byte      // 0=none, 1=scalar derived, 2=scalar expounded (may be overridden by QCC)
	OriginalQuantStyle byte      // Original QCD quantStyle before any QCC override
	GuardBits          int       // Number of guard bits
	StepSizes          []float64 // Quantization step sizes
	Exponents          []int     // Step size exponents (may be overridden by QCC for component 0)
	Mantissas          []int     // Step size mantissas (may be overridden by QCC for component 0)
	// Original QCD values before any QCC override (used for components without QCC)
	OriginalExponents []int // Original QCD exponents
	OriginalMantissas []int // Original QCD mantissas

	// Per-component quantization (from QCC markers)
	// If set, these override the default QCD values for specific components
	// Index = component number
	CompQuantStyle []byte  // Per-component quant style
	CompExponents  [][]int // Per-component exponents
	CompMantissas  [][]int // Per-component mantissas

	// Per-component coding style (from COC markers)
	// If set, these override the default COD values for specific components
	// Index = component number, value is number of decomposition levels
	// A value of -1 means use default (NumDecompLevels)
	CompDecompLevels    []int         // Per-component decomposition levels
	CompPrecinctSizes   [][][2]int    // Per-component precinct sizes [comp][res] (nil = use default)
	CompCodeBlockWidth  []int         // Per-component code block width (0 = use default)
	CompCodeBlockHeight []int         // Per-component code block height (0 = use default)
	CompCodeBlockStyle  []byte        // Per-component code block style (0xFF = use default)
	CompWaveletFilter   []WaveletType // Per-component wavelet filter (0xFF = use default)

	// From POC marker (if present, overrides COD progression order)
	POCEntries []POCEntry // Progression order change entries

	// From TLM marker (tile-part lengths for random access)
	TLMEntries []TLMEntry // Tile-part length entries

	// PPM (Packed Packet Headers in Main header) data
	// When present, packet headers are stored here instead of in the tile data stream
	// Per ITU-T T.800, multiple PPM segments are concatenated in order of Zppm index
	PPMHeaders []byte

	// TilePartOrder records the tile index for each tile-part in codestream order.
	// Used by distributePPMHeaders to correctly assign PPM data per tile-part.
	TilePartOrder []int

	// Computed
	NumXTiles int
	NumYTiles int
	NumTiles  int
	// contains filtered or unexported fields
}

MainHeader contains parsed image metadata

func (*MainHeader) ComponentCodeBlockSize

func (h *MainHeader) ComponentCodeBlockSize(comp int) (int, int)

ComponentCodeBlockSize returns the code block width and height for a component. Per-component COC overrides take precedence over the default COD values.

func (*MainHeader) ComponentCodeBlockStyle

func (h *MainHeader) ComponentCodeBlockStyle(comp int) byte

ComponentCodeBlockStyle returns the code block style for a component.

func (*MainHeader) ComponentDecompLevels

func (h *MainHeader) ComponentDecompLevels(comp int) int

ComponentDecompLevels returns the number of decomposition levels for a component. This accounts for per-component COC marker overrides. If no override exists, returns the default from COD marker.

func (*MainHeader) ComponentHeight

func (h *MainHeader) ComponentHeight(comp int) int

ComponentHeight returns the height of a component accounting for subsampling Per ITU-T T.800 Annex B, equation B-2:

tcy0 = ceil(YOsiz / YRsiz)
tcy1 = ceil(Ysiz / YRsiz)
compHeight = tcy1 - tcy0

This is NOT the same as ceil((Ysiz - YOsiz) / YRsiz) when YOsiz > 0.

func (*MainHeader) ComponentWaveletFilter

func (h *MainHeader) ComponentWaveletFilter(comp int) WaveletType

ComponentWaveletFilter returns the wavelet filter for a component.

func (*MainHeader) ComponentWidth

func (h *MainHeader) ComponentWidth(comp int) int

ComponentWidth returns the width of a component accounting for subsampling Per ITU-T T.800 Annex B, equation B-2:

tcx0 = ceil(XOsiz / XRsiz)
tcx1 = ceil(Xsiz / XRsiz)
compWidth = tcx1 - tcx0

This is NOT the same as ceil((Xsiz - XOsiz) / XRsiz) when XOsiz > 0.

func (*MainHeader) PrecinctSizeForRes

func (h *MainHeader) PrecinctSizeForRes(res, comp int) (int, int)

PrecinctSizeForRes returns the precinct size exponents (PPx, PPy) for a given resolution level and component. Per-component COC overrides take precedence over the default COD precinct sizes.

type POCEntry

type POCEntry struct {
	RSpoc  int  // Resolution level start
	CSpoc  int  // Component start
	LYEpoc int  // Layer end (exclusive)
	REpoc  int  // Resolution level end (exclusive)
	CEpoc  int  // Component end (exclusive)
	Ppoc   byte // Progression order for this entry
}

POCEntry represents a single progression order change entry

type Packet

type Packet struct {
	Layer      int
	Resolution int
	Component  int
	Precinct   int
}

Packet represents a single quality layer packet for a precinct

type PacketEncoder

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

PacketEncoder assembles encoded code blocks into JPEG2000 packets.

func NewPacketEncoder

func NewPacketEncoder(header *MainHeader) *PacketEncoder

NewPacketEncoder creates a new packet encoder.

func (*PacketEncoder) EncodeEmptyPacket

func (pe *PacketEncoder) EncodeEmptyPacket() []byte

EncodeEmptyPacket encodes an empty packet (no code block data). Per ITU-T T.800, this is a single 0-bit followed by byte alignment.

func (*PacketEncoder) EncodePacket

func (pe *PacketEncoder) EncodePacket(
	layer, resolution, component, precinct int,
	subbands []*EncoderSubband,
	passesPerBlock map[int]int,
) []byte

EncodePacket encodes a single packet for one quality layer, one resolution, one component, and one precinct.

passesPerBlock maps a linear block index (y*CodeBlocksX + x) to the number of NEW coding passes to include for that block in this layer. Blocks not present in the map (or with value 0) contribute no data to this packet.

Returns the encoded packet bytes (header + body).

func (*PacketEncoder) EncodePacketWithEPH

func (pe *PacketEncoder) EncodePacketWithEPH(
	layer, resolution, component, precinct int,
	subbands []*EncoderSubband,
	passesPerBlock map[int]int,
) []byte

EncodePacketWithEPH encodes a packet with an EPH (End of Packet Header) marker inserted between the packet header and body. Per ITU-T T.800, the EPH marker is: 0xFF92 (2 bytes).

func (*PacketEncoder) EncodePacketWithSOP

func (pe *PacketEncoder) EncodePacketWithSOP(
	layer, resolution, component, precinct int,
	subbands []*EncoderSubband,
	passesPerBlock map[int]int,
	packetSeqNum int,
) []byte

EncodePacketWithSOP encodes a packet preceded by a SOP (Start of Packet) marker. Per ITU-T T.800, the SOP marker has the structure:

0xFF91 (2 bytes) + Lsop=0x0004 (2 bytes) + Nsop (2 bytes)

where Nsop is the packet sequence number (mod 65536).

func (*PacketEncoder) EncodePacketsLRCP

func (pe *PacketEncoder) EncodePacketsLRCP(
	resolutions [][]*EncoderResolution,
	layerPasses [][][]map[int]int,
) []byte

EncodePacketsLRCP encodes all packets for a tile in LRCP progression order. This is the most common progression order: Layer, Resolution, Component, Position.

resolutions[component][resolution] provides the encoder subbands. layerPasses[layer][component][resolution][blockIdx] provides the number of new passes for each code block in each layer.

Returns all encoded packets concatenated.

type PacketTrace

type PacketTrace struct {
	Layer          int    // Quality layer
	Resolution     int    // Resolution level
	Component      int    // Component index
	PrecinctX      int    // Precinct X index
	PrecinctY      int    // Precinct Y index
	BytePosBefore  int    // Byte position before parsing
	BitPosBefore   int    // Bit position before parsing
	BytePosAfter   int    // Byte position after parsing
	BitPosAfter    int    // Bit position after parsing
	EmptyBit       int    // Value of empty packet indicator (0 or 1)
	NumEntries     int    // Number of code block entries
	DataRead       int    // Bytes of code block data read
	FirstBytes     []byte // First few bytes at parse start (for debugging)
	SubbandEntries []int  // Per-subband entry counts (for debugging)
}

PacketTrace captures parsing state for debugging

type Precinct

type Precinct struct {
	X, Y          int // Precinct index within resolution level
	Width, Height int // Precinct dimensions in samples
	// Code block range within each subband for this precinct
	// For subband sb: iterate cb[cbY0:cbY1][cbX0:cbX1]
	CBX0, CBY0 int // Start code block indices (inclusive)
	CBX1, CBY1 int // End code block indices (exclusive)
}

Precinct is a rectangular region containing code blocks

type RateController

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

RateController performs PCRD-opt rate-distortion optimization.

func NewRateController

func NewRateController(blocks []*EncodedBlock) *RateController

NewRateController creates a rate controller for the given encoded blocks.

func (*RateController) OptimizeLayers

func (rc *RateController) OptimizeLayers(targetBytesPerLayer []int) []LayerAllocation

OptimizeLayers performs multi-layer PCRD-opt. targetBytesPerLayer[i] = cumulative target bytes for layer i. Returns LayerAllocation for each layer.

func (*RateController) OptimizeSingleLayer

func (rc *RateController) OptimizeSingleLayer(targetBytes int) []int

OptimizeSingleLayer finds optimal truncation for a single quality layer to achieve the target byte count. Returns the number of passes to include for each block.

type ResBounds

type ResBounds struct {
	Width, Height int
	X0, Y0        int
}

ResBounds holds resolution-level bounds for DWT synthesis X0, Y0 are the image-space origin (trX0, trY0) used for parity calculation

type ResolutionLevel

type ResolutionLevel struct {
	Level     int // 0 = LL band only, 1+ = HL, LH, HH subbands
	Width     int
	Height    int
	X0, Y0    int // Image-space origin (trX0, trY0) for DWT parity calculation
	Subbands  []*Subband
	Precincts []*Precinct
}

ResolutionLevel represents one resolution level in the wavelet decomposition

type Subband

type Subband struct {
	Type          SubbandType
	Width, Height int
	// X0, Y0 are the subband origin in image-space coordinates (tbX0, tbY0).
	// Per ITU-T T.800 equation B-16, these are derived from resolution bounds (trX0, trY0).
	X0, Y0      int
	CodeBlocksX int // Number of code blocks horizontally
	CodeBlocksY int // Number of code blocks vertically
	CodeBlocks  [][]*CodeBlockInfo

	// Precinct grid parameters.
	// PrcGridX0/Y0: absolute index of the first precinct overlapping the resolution.
	// Computed as floor(trX0 / 2^PPx). This is the RESOLUTION-level grid origin,
	// shared by all subbands within the resolution. Using the subband origin instead
	// would give incorrect results when sbX0/prcW != trX0/(2*prcW).
	PrcGridX0, PrcGridY0 int
	// PrecinctWidth/Height: precinct size in subband coordinates.
	// For detail subbands: 2^(PPx-1) × 2^(PPy-1). For LL: 2^PPx × 2^PPy.
	PrecinctWidth  int
	PrecinctHeight int

	// Per-precinct tag trees (JPEG2000 spec: each precinct has its own tag trees)
	// Indexed by [precinctY * numPrecinctsX + precinctX]
	PrecinctInclusionTrees []*tagTree
	PrecinctZBPTrees       []*tagTree
	NumPrecinctsX          int
	NumPrecinctsY          int
}

Subband within a resolution level

type SubbandType

type SubbandType int

SubbandType represents different subband orientations

const (
	SubbandLL SubbandType = iota
	SubbandHL
	SubbandLH
	SubbandHH
)

func (SubbandType) String

func (s SubbandType) String() string

type TLMEntry

type TLMEntry struct {
	TileIndex   int // Tile index (0-65534, or -1 if not specified in TLM)
	TilePartLen int // Length of tile-part in bytes (includes SOT marker)
}

TLMEntry represents a tile-part length entry from TLM marker. Per ITU-T T.800, TLM markers provide tile-part lengths for random access.

type Tile

type Tile struct {
	Index     int
	X0, Y0    int // Tile origin in image coords
	X1, Y1    int // Tile end in image coords
	TileParts []*TilePart

	// ROI (Region of Interest) shift values per component
	// From RGN marker in tile-part header
	// If ROIShift[c] > 0, coefficients for component c need to be de-shifted
	ROIShift []int

	// Tile-specific coding style overrides from tile-part header COD marker
	// If HasTileCOD is true, use these instead of main header values
	HasTileCOD             bool
	TileProgressionOrder   byte // SGcod: progression order (0=LRCP, 1=RLCP, 2=RPCL, 3=PCRL, 4=CPRL)
	TileNumLayers          int  // SGcod: number of layers
	TileCodeBlockStyle     byte
	TileNumDecompLevels    int
	TileCodeBlockWidthExp  byte // SPcod: code block width exponent (offset from 2)
	TileCodeBlockHeightExp byte // SPcod: code block height exponent (offset from 2)
	TileWaveletFilter      WaveletType
	TilePrecinctSizes      [][2]byte // Per-resolution precinct sizes (PPx, PPy) from tile COD

	// Tile-specific quantization overrides from tile-part header QCD marker
	// If HasTileQCD is true, use these instead of main header QCD values
	HasTileQCD     bool
	TileQuantStyle byte
	TileGuardBits  int
	TileExponents  []int
	TileMantissas  []int

	// PPT (Packed Packet Headers) data
	// When present, packet headers are stored here instead of in the tile data stream
	// Per ITU-T T.800, multiple PPT segments are concatenated in order of Zppt index
	PPTHeaders []byte

	// POC (Progression Order Change) entries from tile-part header
	// When present, overrides main header POC/COD progression order for this tile
	POCEntries []POCEntry
	// contains filtered or unexported fields
}

Tile represents a single tile

type TileDecoder

type TileDecoder struct {

	// Trace collects packet parsing traces when non-nil (for debugging)
	Trace []PacketTrace
	// contains filtered or unexported fields
}

TileDecoder handles tile-level packet parsing and decoding

func (*TileDecoder) EnableTracing

func (td *TileDecoder) EnableTracing()

EnableTracing enables packet parsing trace collection

type TilePart

type TilePart struct {
	TileIndex int
	PartIndex int
	Length    int
	Data      []byte // Coded bitstream data
}

TilePart represents one tile-part

type TruncationPoint

type TruncationPoint struct {
	BlockIndex int     // Index into the blocks array
	PassIndex  int     // Number of passes to include (1-based: pass 0 means include first pass)
	Bytes      int     // Cumulative bytes up to this pass
	Distortion float64 // Cumulative distortion reduction up to this pass
	Slope      float64 // R-D slope = ΔD/ΔR (distortion reduction per byte)
}

TruncationPoint represents a truncation point for a code block pass.

type WaveletType

type WaveletType int

WaveletType indicates the wavelet filter used

const (
	Wavelet53 WaveletType = iota // 5/3 reversible (lossless)
	Wavelet97                    // 9/7 irreversible (lossy)
)

Jump to

Keyboard shortcuts

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