progressive

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// MaxScans is the maximum number of scans allowed (security limit)
	MaxScans = 100

	// MaxCoefficients is the maximum coefficient buffer size (512MB / 4 bytes per int)
	MaxCoefficients = 134217728

	// MaxBlocksPerComponent prevents OOM attacks
	MaxBlocksPerComponent = 16777216 // 16M blocks

	// MaxSpectralIndex is the maximum DCT coefficient index (0-63)
	MaxSpectralIndex = 63

	// MaxSuccessiveApprox is the maximum successive approximation value
	MaxSuccessiveApprox = 13

	// MaxComponents is the maximum number of color components
	MaxComponents = 4

	// ValidPrecision8 is 8-bit sample precision
	ValidPrecision8 = 8

	// ValidPrecision12 is 12-bit sample precision
	ValidPrecision12 = 12
)

Constants for progressive JPEG limits

View Source
const MaxEOBRun = 32767

MaxEOBRun is the maximum allowed EOB run length (2^14 for EOB14)

Variables

View Source
var (
	// ErrInvalidScanHeader is the umbrella sentinel returned by the SOS
	// validator whenever any T.81 G.1.1.1.1 rule is violated. Specific
	// violations wrap this with a descriptive message.
	ErrInvalidScanHeader = errors.New("invalid progressive SOS scan header")

	// ErrInvalidDCScan indicates a DC scan (Ss=0) violates T.81 G.1.1.1.1:
	// DC scans require Se=0.
	ErrInvalidDCScan = errors.New("invalid DC scan parameters")

	// ErrInvalidACScan indicates an AC scan (Ss>=1) violates T.81 G.1.1.1.1:
	// AC scans require Se>=Ss, Se<=63, and Nf=1 (a single component).
	ErrInvalidACScan = errors.New("invalid AC scan parameters")

	// ErrInvalidRefinement indicates a refinement scan (Ah!=0) has Al that
	// is not exactly Ah-1, violating T.81 G.1.1.1.1's successive-approximation
	// rule.
	ErrInvalidRefinement = errors.New("invalid successive-approximation refinement")
)

Sentinel errors for SOS scan-header validation per ITU-T T.81 §G.1.1.1.1. These are wrappable (%w) so callers can distinguish a scan-header rejection from other validation failures (precision, dimensions, safe-arithmetic) with errors.Is.

View Source
var ErrInvalidMarker = fmt.Errorf("invalid marker")

ErrInvalidMarker indicates an invalid marker was encountered during progressive JPEG parsing.

Functions

This section is empty.

Types

type BitReader

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

BitReader reads bits from an io.Reader with byte stuffing handling. In JPEG entropy-coded segments, 0xFF bytes are followed by 0x00 (stuffing).

func NewBitReader

func NewBitReader(r io.Reader) *BitReader

NewBitReader creates a new bit reader.

func (*BitReader) ReadBit

func (br *BitReader) ReadBit() (int, error)

ReadBit reads a single bit from the stream. Returns the bit value (0 or 1) and an error if EOF or read error.

func (*BitReader) ReadBits

func (br *BitReader) ReadBits(n int) (int, error)

ReadBits reads n bits from the stream. Returns the value and an error if EOF or read error.

func (*BitReader) Reset

func (br *BitReader) Reset()

Reset resets the bit reader state.

type CoefficientBuffer

type CoefficientBuffer struct {
	// Width is the image width in pixels
	Width int

	// Height is the image height in pixels
	Height int

	// ComponentCount is the number of color components
	ComponentCount int

	// BlocksH is the number of 8x8 blocks horizontally
	BlocksH int

	// BlocksV is the number of 8x8 blocks vertically
	BlocksV int
	// contains filtered or unexported fields
}

CoefficientBuffer stores DCT coefficients across progressive scans. In progressive JPEG, coefficients are built up over multiple scans, so the buffer must persist and accumulate data across scans.

func NewCoefficientBuffer

func NewCoefficientBuffer(width, height, components int, validator Validator) (*CoefficientBuffer, error)

NewCoefficientBuffer creates a new coefficient buffer for the given image dimensions. Returns an error if dimensions are invalid or would cause memory exhaustion.

func (*CoefficientBuffer) GetBlock

func (cb *CoefficientBuffer) GetBlock(component, block int) []int

GetBlock returns all 64 coefficients for a block. Returns nil if indices are invalid.

func (*CoefficientBuffer) GetCoefficient

func (cb *CoefficientBuffer) GetCoefficient(component, block, coeff int) int

GetCoefficient retrieves a coefficient value. Returns 0 if indices are out of bounds (for safety in read operations).

func (*CoefficientBuffer) IsNonZero

func (cb *CoefficientBuffer) IsNonZero(component, block, coeff int) bool

IsNonZero returns true if the coefficient has been set to a non-zero value.

func (*CoefficientBuffer) RefineAC

func (cb *CoefficientBuffer) RefineAC(component, block, coeff, bit, al int) error

RefineAC adds a refinement bit to an AC coefficient. For refinement scan (Ah != 0), a single bit is added at position Al.

func (*CoefficientBuffer) RefineDC

func (cb *CoefficientBuffer) RefineDC(component, block, bit, al int) error

RefineDC adds a refinement bit to the DC coefficient. For refinement scan (Ah != 0), a single bit is added at position Al.

func (*CoefficientBuffer) Reset

func (cb *CoefficientBuffer) Reset()

Reset clears all coefficients to zero. Useful for starting a new image decode.

func (*CoefficientBuffer) SetACFirstScan

func (cb *CoefficientBuffer) SetACFirstScan(component, block, coeff, value, al int) error

SetACFirstScan sets an AC coefficient for a block in the first scan. For first scan (Ah=0), the value is shifted left by Al bits.

func (*CoefficientBuffer) SetCoefficient

func (cb *CoefficientBuffer) SetCoefficient(component, block, coeff, value int) error

SetCoefficient sets a coefficient value with bounds checking.

func (*CoefficientBuffer) SetDCFirstScan

func (cb *CoefficientBuffer) SetDCFirstScan(component, block, value, al int) error

SetDCFirstScan sets the DC coefficient for a block in the first scan. For first scan (Ah=0), the value is shifted left by Al bits. This stores the most significant bits, leaving lower bits for refinement.

type Component

type Component struct {
	// ID is the component identifier (1-255)
	ID int

	// HorizontalSampling is the horizontal sampling factor (1-4)
	HorizontalSampling int

	// VerticalSampling is the vertical sampling factor (1-4)
	VerticalSampling int

	// QuantTableID is the quantization table selector (0-3)
	QuantTableID int
}

Component represents a single color component in the frame.

type DefaultValidator

type DefaultValidator struct{}

DefaultValidator implements Validator with standard checks.

func NewValidator

func NewValidator() *DefaultValidator

NewValidator creates a new default validator.

func (*DefaultValidator) SafeAdd

func (*DefaultValidator) SafeAdd(a, b int) (int, error)

SafeAdd performs addition with overflow checking.

func (*DefaultValidator) SafeMultiply

func (*DefaultValidator) SafeMultiply(a, b int) (int, error)

SafeMultiply performs multiplication with overflow checking.

func (*DefaultValidator) SafeSubtract

func (*DefaultValidator) SafeSubtract(a, b int) (int, error)

SafeSubtract performs subtraction with underflow checking.

func (*DefaultValidator) ValidateComponentCount

func (*DefaultValidator) ValidateComponentCount(count int) error

ValidateComponentCount validates number of components.

func (*DefaultValidator) ValidateDimensions

func (*DefaultValidator) ValidateDimensions(width, height int) error

ValidateDimensions validates width and height.

func (*DefaultValidator) ValidatePrecision

func (*DefaultValidator) ValidatePrecision(precision int) error

ValidatePrecision validates sample precision (must be 8 or 12 for progressive DCT).

func (*DefaultValidator) ValidateScanHeader

func (v *DefaultValidator) ValidateScanHeader(ss, se, ah, al, nf int) error

ValidateScanHeader enforces the SOS scan-header constraints defined in ITU-T T.81 §G.1.1.1.1 for progressive-mode JPEGs. The caller passes the numeric tuple parsed from the SOS marker — spectral start/end, successive- approximation high/low, and the component count Nf — and receives a wrapped error describing the exact violated rule on failure, or nil on success.

Rules enforced, per T.81 G.1.1.1.1:

  • DC scan (Ss=0): Se must equal 0; any Nf in 1..MaxComponents is allowed.
  • AC scan (Ss>=1): Se must satisfy Ss<=Se<=63 and Nf must equal 1 (AC scans may contain only a single component).
  • First scan (Ah=0): no refinement constraint on Al beyond the general 0..13 range handled below.
  • Refinement scan (Ah!=0): Al must equal Ah-1, matching the successive- approximation one-bit-at-a-time rule.

Errors are returned wrapping the appropriate sentinel (ErrInvalidDCScan, ErrInvalidACScan, ErrInvalidRefinement) via fmt.Errorf("...: %w", ...) so callers can dispatch on errors.Is. ValidateScanHeader itself does not panic; out-of-range scalar inputs (Ss/Se outside 0..63, Ah/Al outside 0..13, or Nf outside 1..MaxComponents) fall through to ErrInvalidScanHeader with a descriptive wrapper.

Ordering matters: scalar-range checks run first so the DC/AC rules below can assume bounded inputs. The Se<Ss check is intentionally deferred to the AC branch rather than subsumed by ValidateSpectralSelection, so an AC-mode violation (Ss>=1, Se<Ss) wraps ErrInvalidACScan rather than the umbrella ErrInvalidScanHeader — callers dispatching on errors.Is(err, ErrInvalidACScan) get a more specific signal.

func (*DefaultValidator) ValidateSpectralSelection

func (*DefaultValidator) ValidateSpectralSelection(ss, se int) error

ValidateSpectralSelection validates Ss and Se parameters.

func (*DefaultValidator) ValidateSuccessiveApproximation

func (*DefaultValidator) ValidateSuccessiveApproximation(ah, al int) error

ValidateSuccessiveApproximation validates Ah and Al parameters.

type EOBTracker

type EOBTracker struct {
	// EOBRun is the remaining number of blocks to skip
	EOBRun int
}

EOBTracker tracks End-of-Block runs in progressive AC scans. In progressive JPEG, EOBn symbols (n=0-14) indicate that the next 2^n blocks have no more non-zero coefficients in the current spectral band.

func NewEOBTracker

func NewEOBTracker() *EOBTracker

NewEOBTracker creates a new EOB run tracker.

func (*EOBTracker) ConsumeEOB

func (e *EOBTracker) ConsumeEOB() bool

ConsumeEOB decrements the EOB run counter. Returns true if there was a run to consume, false if run was already 0.

func (*EOBTracker) HasEOBRun

func (e *EOBTracker) HasEOBRun() bool

HasEOBRun returns true if there are remaining blocks in the EOB run.

func (*EOBTracker) Reset

func (e *EOBTracker) Reset()

Reset clears the EOB run counter.

func (*EOBTracker) SetEOBRun

func (e *EOBTracker) SetEOBRun(run int)

SetEOBRun sets the EOB run length. This is called when an EOBn symbol is decoded.

func (*EOBTracker) SetEOBRunSafe

func (e *EOBTracker) SetEOBRunSafe(run int) error

SetEOBRunSafe sets the EOB run length with overflow protection.

type Frame

type Frame struct {
	// Precision is the sample precision in bits (8 or 12 for progressive)
	Precision int

	// Height is the image height in pixels
	Height int

	// Width is the image width in pixels
	Width int

	// Components contains the color component specifications
	Components []Component
}

Frame represents a progressive JPEG frame (SOF2).

type FrameParser

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

FrameParser parses progressive JPEG frame markers (SOF2).

func NewFrameParser

func NewFrameParser(validator Validator) *FrameParser

NewFrameParser creates a new frame parser with the given validator.

func (*FrameParser) ParseSOF2

func (p *FrameParser) ParseSOF2(r io.Reader) (*Frame, error)

ParseSOF2 parses a SOF2 (progressive DCT) frame marker. The reader should be positioned at the start of the marker (0xFF 0xC2).

type HuffmanTable

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

HuffmanTable represents a Huffman decoding table.

func NewHuffmanTable

func NewHuffmanTable(bits [17]int, huffval []int) *HuffmanTable

NewHuffmanTable creates a new Huffman table from BITS and HUFFVAL. bits[i] is the number of codes with length i+1 (bits[0] unused). huffval contains the symbol values in order.

func (*HuffmanTable) Decode

func (ht *HuffmanTable) Decode(br *BitReader) (int, error)

Decode decodes one symbol using this Huffman table.

type Scan

type Scan struct {
	// Components lists the components in this scan
	Components []ScanComponent

	// SpectralStart is the first DCT coefficient in this scan (Ss, 0-63)
	SpectralStart int

	// SpectralEnd is the last DCT coefficient in this scan (Se, 0-63)
	SpectralEnd int

	// SuccApproxHigh is the successive approximation bit position high (Ah, 0-13)
	SuccApproxHigh int

	// SuccApproxLow is the successive approximation bit position low (Al, 0-13)
	SuccApproxLow int
}

Scan represents a single scan in a progressive JPEG.

func (*Scan) IsACScan

func (s *Scan) IsACScan() bool

IsACScan returns true if this scan contains AC coefficients.

func (*Scan) IsDCScan

func (s *Scan) IsDCScan() bool

IsDCScan returns true if this scan contains only DC coefficients.

func (*Scan) IsFirstScan

func (s *Scan) IsFirstScan() bool

IsFirstScan returns true if this is the first scan for its coefficients.

func (*Scan) IsRefinementScan

func (s *Scan) IsRefinementScan() bool

IsRefinementScan returns true if this is a refinement scan.

type ScanComponent

type ScanComponent struct {
	// ComponentSelector identifies the component (matches Component.ID)
	ComponentSelector int

	// DCTableSelector is the DC Huffman/arithmetic table (0-3)
	DCTableSelector int

	// ACTableSelector is the AC Huffman/arithmetic table (0-3)
	ACTableSelector int
}

ScanComponent represents a component's parameters within a scan.

type ScanDecoder

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

ScanDecoder decodes entropy-coded data from progressive JPEG scans. It handles spectral selection and successive approximation for both first scans (Ah=0) and refinement scans (Ah>0).

func NewScanDecoder

func NewScanDecoder(frame *Frame, validator Validator) (*ScanDecoder, error)

NewScanDecoder creates a new scan decoder for the given frame.

func (*ScanDecoder) DecodeScan

func (sd *ScanDecoder) DecodeScan(r io.Reader, scan *Scan) error

DecodeScan decodes a single progressive scan. The reader should be positioned at the start of entropy-coded data.

func (*ScanDecoder) GetCoefficientBuffer

func (sd *ScanDecoder) GetCoefficientBuffer() *CoefficientBuffer

GetCoefficientBuffer returns the accumulated coefficient buffer.

func (*ScanDecoder) GetCoefficients

func (sd *ScanDecoder) GetCoefficients() []int

GetCoefficients returns all accumulated DCT coefficients as a flat array. Layout: blocks in raster order, each block contains 64 coefficients.

func (*ScanDecoder) Reset

func (sd *ScanDecoder) Reset()

Reset resets the decoder for a new image.

func (*ScanDecoder) SetHuffmanTable

func (sd *ScanDecoder) SetHuffmanTable(tableClass, tableID int, table *HuffmanTable) error

SetHuffmanTable sets a Huffman table for decoding. tableClass: 0 for DC, 1 for AC tableID: 0-3

type ScanParser

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

ScanParser parses progressive JPEG scan markers (SOS).

func NewScanParser

func NewScanParser(validator Validator) *ScanParser

NewScanParser creates a new scan parser with the given validator.

func (*ScanParser) ParseSOS

func (p *ScanParser) ParseSOS(r io.Reader) (*Scan, error)

ParseSOS parses a SOS (Start of Scan) marker for progressive JPEG. The reader should be positioned at the start of the marker (0xFF 0xDA).

type ScanTracker

type ScanTracker struct {
	// ScanCount is the number of scans processed
	ScanCount int
}

ScanTracker tracks the number of scans processed to prevent infinite loops. Progressive JPEGs typically have 10-20 scans, so 100 is a generous limit.

func NewScanTracker

func NewScanTracker() *ScanTracker

NewScanTracker creates a new scan tracker.

func (*ScanTracker) IncrementScan

func (s *ScanTracker) IncrementScan() error

IncrementScan increments the scan counter and checks against the limit. Returns an error if the maximum number of scans has been exceeded.

func (*ScanTracker) Reset

func (s *ScanTracker) Reset()

Reset resets the scan counter to zero.

type Validator

type Validator interface {
	// ValidatePrecision validates sample precision (must be 8 or 12).
	ValidatePrecision(precision int) error

	// ValidateDimensions validates width and height.
	ValidateDimensions(width, height int) error

	// ValidateSpectralSelection validates Ss and Se parameters.
	ValidateSpectralSelection(ss, se int) error

	// ValidateSuccessiveApproximation validates Ah and Al parameters.
	ValidateSuccessiveApproximation(ah, al int) error

	// ValidateComponentCount validates number of components.
	ValidateComponentCount(count int) error

	// SafeMultiply performs multiplication with overflow checking.
	SafeMultiply(a, b int) (int, error)

	// SafeAdd performs addition with overflow checking.
	SafeAdd(a, b int) (int, error)

	// SafeSubtract performs subtraction with underflow checking.
	SafeSubtract(a, b int) (int, error)
}

Validator provides validation for progressive JPEG parameters.

Jump to

Keyboard shortcuts

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