Skip to main content

Decoder

Struct Decoder 

Source
pub struct Decoder<'a> { /* private fields */ }
Expand description

JPEG decoder. Orchestrates the full decoding pipeline.

§Threading

Decoder is Send — a configured decoder can move to another thread (rayon, tokio::task::spawn_blocking) and decode there (issue #384). It is deliberately not Sync: in-decode state lives behind interior mutability (RefCell) and the installed callbacks are Send-only boxes, so one decoder serves one thread at a time — upstream libjpeg-turbo’s per-cinfo rule. Our own C ABI shim is stricter still: a cinfo may not leave the thread that created it (docs/ABI_COMPATIBILITY.md, “Threading contract”). Decode the same bytes concurrently by giving each thread its own Decoder; construction from &[u8] is cheap (header parse only).

Implementations§

Source§

impl<'a> Decoder<'a>

Source

pub fn new(data: &'a [u8]) -> Result<Self>

Parse the JPEG headers in data and return a configurable decoder. No entropy decoding and no pixel work happen here, but for progressive and non-interleaved streams locating the scan boundaries walks the entropy bytes, so worst-case probe time scales with the compressed input length (still far cheaper than a decode). Suitable as a probe (dimensions, Decoder::exif_orientation, ICC/EXIF/XMP metadata) even when no decode follows. Uses DecodeLimits::default; use Decoder::new_with_limits to bound resource use differently.

Source

pub fn new_with_limits(data: &'a [u8], limits: DecodeLimits) -> Result<Self>

Like Self::new, but the limits apply from marker parsing onward: a max_scans tighter than the parse default bounds ScanInfo buffering during the header walk itself, not just at decode time (issue #355).

Source

pub fn new_with_tables( body_data: &'a [u8], tables: &TablesOnlyState, ) -> Result<Self>

Create a decoder for a body-only abbreviated stream using preloaded tables.

The body_data must contain SOF and SOS markers but may omit DQT and DHT. Tables from tables are injected into the decoder’s internal state before decoding.

Matches libjpeg-turbo’s abbreviated compressed data datastream handling: use read_header() to get a TablesOnlyState, then this function to decode the body-only stream.

Source

pub fn exif_orientation(&self) -> Option<u8>

EXIF orientation (1-8) from the already-parsed headers, without any pixel decode (issue #391). Decoder::new is a header parse only, so probing a camera JPEG’s orientation costs no decoding:

let decoder = libjpeg_turbo_rs::Decoder::new(&jpeg)?;
// This fixture carries no EXIF; a camera JPEG returns Some(1..=8).
// Map 2-8 with TransformOp::from_exif_orientation (lossless, DCT
// domain) or Image::apply_orientation (pixels).
assert_eq!(decoder.exif_orientation(), None);
Source

pub fn header(&self) -> &FrameHeader

The parsed frame header: dimensions, per-component sampling, precision, progressive/lossless flags. Available immediately after Decoder::new, before any pixel decode.

Source

pub fn density(&self) -> &DensityInfo

Pixel density parsed from the JFIF APP0 marker (or DensityInfo::default() if no JFIF was present). Mirrors stock libjpeg’s cinfo.density_unit / X_density / Y_density exposed after jpeg_read_header.

Source

pub fn saw_jfif_marker(&self) -> bool

Whether the source carried a JFIF APP0 marker (regardless of the density values it contained). Mirrors stock libjpeg’s cinfo.saw_JFIF_marker.

Source

pub fn jfif_version(&self) -> (u8, u8)

JFIF version bytes from the APP0 marker. Returns (0, 0) if saw_jfif_marker() is false.

Source

pub fn is_arithmetic(&self) -> bool

Whether the source uses arithmetic entropy coding (SOF9 / SOF10 / SOF11).

Returns true for arithmetic-coded streams and false for Huffman-coded streams (SOF0 / SOF1 / SOF2 / SOF3). Mirrors stock libjpeg’s cinfo.arith_code populated by jpeg_read_header.

Source

pub fn set_output_format(&mut self, format: PixelFormat)

Set the desired output pixel format.

Source

pub fn set_scale(&mut self, scale: ScalingFactor)

Set the decompression scaling factor (e.g., 1/2, 1/4, 1/8).

Source

pub fn set_lenient(&mut self, lenient: bool)

Enable lenient mode: continue decoding on errors, filling corrupt areas with gray.

Source

pub fn set_crop(&mut self, x: usize, width: usize)

Set horizontal crop region. Offsets are auto-aligned to iMCU boundaries.

Source

pub fn set_crop_y(&mut self, y: usize, height: usize)

Set only the vertical crop range, leaving any horizontal crop untouched. MCU rows fully outside the range skip IDCT during decoding (issue #383: backs StreamingDecoder::skip_scanlines).

Source

pub fn output_height(&self) -> usize

Rows a decode will actually emit: the scaled frame height, except on the 12-bit and lossless paths, which bypass scaled decode (see output_buffer_size). crop_y/crop_height are interpreted in these output rows, matching C, where jpeg_skip_scanlines validates against cinfo->output_height (jdapistd.c).

Source

pub fn set_crop_region( &mut self, x: usize, y: usize, width: usize, height: usize, )

Set full crop region (horizontal + vertical). MCU rows outside the vertical range will skip IDCT during decoding.

Source

pub fn set_stop_on_warning(&mut self, stop: bool)

Treat warnings as fatal errors.

Source

pub fn set_max_pixels(&mut self, limit: usize)

Set maximum allowed image size in pixels. Reject images exceeding this.

Source

pub fn set_max_memory(&mut self, limit: usize)

Set maximum memory usage in bytes.

Source

pub fn set_scan_limit(&mut self, limit: u32)

Set maximum number of progressive scans before error.

Source

pub fn set_limits(&mut self, limits: DecodeLimits)

Configure all decoder resource limits at once (issue #355).

Defaults (DecodeLimits::default) are permissive — they accept everything djpeg accepts in the corpus gates while rejecting the pathological corner (a header-only 65535x65535 SOF exceeds the default max_pixels before any plane allocation). Use DecodeLimits::strict for zune-like tight bounds. Exceeding a limit is a typed JpegError::LimitExceeded, never a panic. Note on max_scans: marker parsing happens in the constructor, bounded by the construction-time cap (new uses the 8192 default; new_with_limits threads the caller’s value, higher or lower). Setting a different max_scans here affects only the decode-time check — a stream needing a larger parse cap must be constructed with new_with_limits.

Source

pub fn limits(&self) -> &DecodeLimits

The currently configured resource limits.

Source

pub fn set_fast_upsample(&mut self, fast: bool)

Enable or disable fast (nearest-neighbor) upsampling.

Source

pub fn jpeg_color_space(&self) -> ColorSpace

Get the JPEG color space detected from the file header.

Maps component count and Adobe APP14 marker to a ColorSpace value, matching libjpeg-turbo’s jpeg_color_space behavior.

Source

pub fn jpeg_subsampling(&self) -> Subsampling

Get the chroma subsampling detected from the SOF component sampling factors.

Compares luma vs chroma sampling factors to determine the standard subsampling mode. Returns Subsampling::Unknown for grayscale (caller should check component count and map to TJSAMP_GRAY=3).

Source

pub fn set_fast_dct(&mut self, fast: bool)

Enable or disable fast DCT for decoding.

Source

pub fn set_dct_method(&mut self, method: DctMethod)

Set the DCT/IDCT method for decoding.

Source

pub fn set_block_smoothing(&mut self, smooth: bool)

Enable or disable inter-block smoothing.

Source

pub fn set_output_colorspace(&mut self, cs: ColorSpace)

Override the output color space.

Source

pub fn set_dither_565(&mut self, dither: bool)

Enable or disable ordered dithering for RGB565 output.

When enabled, applies a 4x4 ordered dither pattern before truncating 8-bit RGB to 5-6-5, reducing visible banding in smooth gradients. Matches libjpeg-turbo’s dithered RGB565 output mode.

Source

pub fn set_merged_upsample(&mut self, enabled: bool)

Enable merged upsampling optimization (combines upsample + color convert).

When enabled and subsampling is 4:2:0 or 4:2:2, uses a merged path that performs chroma upsampling and YCbCr->RGB conversion in a single pass. This avoids writing upsampled chroma to intermediate buffers, improving cache behavior. Slightly less accurate than separate fancy upsample because merged uses box-filter (nearest-neighbor) chroma replication.

Source

pub fn save_markers(&mut self, config: MarkerSaveConfig)

Configure which markers to save during decoding.

By default, the decoder only parses known markers (JFIF, ICC, EXIF, Adobe, COM) and discards unknown APP markers. Call this to preserve arbitrary APP/COM markers in the decoded Image.saved_markers field.

This re-parses the JPEG header with the new configuration.

Source

pub fn saved_markers(&self) -> &[SavedMarker]

Saved APP/COM markers from the source JPEG, populated by the most recent header parse. Empty unless save_markers() has been called with a non-None config (or the underlying parser was constructed with one). Used by C-ABI consumers (crates/libjpeg-turbo-rs-capi) that need to re-emit source markers verbatim during transcode.

Source

pub fn with_output_format(self, format: PixelFormat) -> Self

Chainable Decoder::set_output_format.

use libjpeg_turbo_rs::{Decoder, PixelFormat};
let image = Decoder::new(&jpeg)?
    .with_output_format(PixelFormat::Bgra)
    .with_block_smoothing(false)
    .decode_image()?;
assert_eq!(image.pixel_format, PixelFormat::Bgra);
Source

pub fn with_scale(self, scale: ScalingFactor) -> Self

Chainable Decoder::set_scale.

Source

pub fn with_lenient(self, lenient: bool) -> Self

Source

pub fn with_crop(self, x: usize, width: usize) -> Self

Chainable Decoder::set_crop.

Source

pub fn with_crop_y(self, y: usize, height: usize) -> Self

Source

pub fn with_crop_region( self, x: usize, y: usize, width: usize, height: usize, ) -> Self

Source

pub fn with_stop_on_warning(self, stop: bool) -> Self

Source

pub fn with_max_pixels(self, limit: usize) -> Self

Source

pub fn with_max_memory(self, limit: usize) -> Self

Source

pub fn with_scan_limit(self, limit: u32) -> Self

Source

pub fn with_limits(self, limits: DecodeLimits) -> Self

Source

pub fn with_fast_upsample(self, fast: bool) -> Self

Source

pub fn with_fast_dct(self, fast: bool) -> Self

Source

pub fn with_dct_method(self, method: DctMethod) -> Self

Source

pub fn with_block_smoothing(self, smooth: bool) -> Self

Source

pub fn with_output_colorspace(self, cs: ColorSpace) -> Self

Source

pub fn with_dither_565(self, dither: bool) -> Self

Source

pub fn with_merged_upsample(self, enabled: bool) -> Self

Source

pub fn with_save_markers(self, config: MarkerSaveConfig) -> Self

Chainable Decoder::save_markers.

Like save_markers, a marker re-parse failure is swallowed and previously parsed metadata stays in effect — check Decoder::saved_markers afterwards if the distinction matters.

Source

pub fn with_marker_processor<F>(self, marker_type: u8, processor: F) -> Self
where F: Fn(&[u8]) -> Option<Vec<u8>> + Send + 'static,

Source

pub fn with_resync_strategy<S>(self, strategy: S) -> Self
where S: RestartResyncStrategy + Send + 'static,

Source

pub fn set_marker_processor<F>(&mut self, marker_type: u8, processor: F)
where F: Fn(&[u8]) -> Option<Vec<u8>> + Send + 'static,

Register a custom marker processor callback for a specific marker type.

The callback must be Send: the decoder itself is Send (issue #384), so everything installed into it travels across threads with it.

Source

pub fn set_resync_strategy<S>(&mut self, strategy: S)
where S: RestartResyncStrategy + Send + 'static,

Install a custom RestartResyncStrategy to handle RST-marker desync events (mirrors C libjpeg-turbo’s jpeg_resync_to_restart hook).

When the decoder encounters a restart marker whose RST number does not match the expected counter — or when no RST marker is found at the expected position — the strategy’s on_desync method is consulted. The returned ResyncAction tells the decoder whether to continue (accept the observed marker), skip to the next RST in the stream, or abort with a CorruptData error.

If no strategy is installed, the decoder defaults to Continue — the historical Rust behavior of unconditionally accepting whatever RST marker it finds.

Source

pub fn decode(data: &'a [u8]) -> Result<Image>

Source

pub fn decode_to(data: &'a [u8], format: PixelFormat) -> Result<Image>

Source

pub fn decode_image(&self) -> Result<Image>

Decode the full image into an owned Image using the configuration set on this decoder (output format, scaling, crop, leniency, …). To decode into a caller-owned buffer, see Decoder::decode_image_into (which avoids the per-frame output allocation on the standard direct-output paths; its docs list the staged exceptions).

Source

pub fn output_buffer_size(&self) -> Result<usize>

Bytes decode_image_into needs for this stream with the current decoder options. Exact for the standard paths; a safe upper bound when an output-colourspace override is active (sized at 4 bytes/pixel) or when cropping trims the image below the MCU-aligned estimate.

Source

pub fn decode_image_into(&self, out: &mut [u8]) -> Result<ImageInfo>

Decode into a caller-provided buffer, returning the metadata Image would carry minus the pixel Vec (issue #354).

out must hold at least Self::output_buffer_size bytes; a short buffer is a typed JpegError::BufferTooSmall, never a panic or truncation. The standard baseline/progressive output paths (grayscale, 4:4:4, and every streamed subsampling mode) write pixels directly into out with no output-sized heap allocation; the remaining paths (CMYK, 12-bit, lossless, output colourspace overrides, vertical crop) stage through an internal buffer and copy, which is still allocation-neutral versus decode_image and byte-identical to it.

On error the contents of out are unspecified: a decode may have written part of the frame before failing.

Source

pub fn decode_raw(self) -> Result<RawImage>

Decode JPEG to raw downsampled component planes.

Returns component planes at their native (potentially subsampled) resolution, without performing color conversion or upsampling. This matches libjpeg-turbo’s jpeg_read_raw_data() functionality.

Auto Trait Implementations§

§

impl<'a> !Freeze for Decoder<'a>

§

impl<'a> !RefUnwindSafe for Decoder<'a>

§

impl<'a> !Sync for Decoder<'a>

§

impl<'a> !UnwindSafe for Decoder<'a>

§

impl<'a> Send for Decoder<'a>

§

impl<'a> Unpin for Decoder<'a>

§

impl<'a> UnsafeUnpin for Decoder<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.