image API reference Changelog View on GitHub

API reference

Image decoders and encoders in Zig with no C: PNG, JPEG, GIF, WebP, TIFF, JPEG XL, and more. Nothing allocates: callers own every buffer. Each format is a namespace with a Decoder, and an encode once it has an encoder (see EncodeError); Decoder here decodes any of them, and detect names a file's format.

module pixel

src

Pixel formats and the caller's pixel buffer.

more

A decoder writes the PixelFormat the caller asks for and reports the source's native one (Config.native), so a caller can ask for that and skip conversion. Every format is interleaved. Samples wider than a byte are in the machine's byte order, so a 16-bit buffer can be viewed as []u16 and a float one as []f32 when it is aligned.

Types

enum PixelFormat

src
pub const PixelFormat = enum(u8)

How a pixel is laid out in memory: channel order, sample type, and whether color is premultiplied by alpha.

Fields

gray8 gray8
gray_alpha8 gray_alpha8
gray_alpha8_premul gray_alpha8_premul
rgb8 rgb8
bgr8 bgr8
rgba8 rgba8
rgba8_premul rgba8_premul
bgra8 bgra8
bgra8_premul bgra8_premul
gray16 gray16
gray_alpha16 gray_alpha16
gray_alpha16_premul gray_alpha16_premul
rgb16 rgb16
bgr16 bgr16
rgba16 rgba16
rgba16_premul rgba16_premul
bgra16 bgra16
bgra16_premul bgra16_premul
rgba_f32 rgba_f32

32-bit float samples, nominally 0 to 1, for float and HDR sources.

rgba_f32_premul rgba_f32_premul
rgb_f32 rgb_f32
gray_f32 gray_f32
cmyk8 cmyk8

Cyan, magenta, yellow, and black, each inverted (the maximum is no ink) as Adobe's CMYK JPEGs store them and libjpeg-turbo returns them, so that all-zero bytes are black here as in every other format; TIFF's and PDF's ink amounts are the maximum minus these. To color they convert naively, as libjpeg-turbo does: each of R, G, and B is ink * black / max, rounded.

cmyk16 cmyk16

Functions

pub fn sample(f: PixelFormat) Sample

src

pub fn channelCount(f: PixelFormat) usize

src

The number of samples per pixel: 1 to 4.

pub fn bytesPerSample(f: PixelFormat) usize

src

pub fn bytesPerPixel(f: PixelFormat) usize

src

pub fn hasAlpha(f: PixelFormat) bool

src

pub fn isPremultiplied(f: PixelFormat) bool

src

pub fn isGray(f: PixelFormat) bool

src

pub fn isCmyk(f: PixelFormat) bool

src

pub fn channels(f: PixelFormat) Channels

src

pub fn rowBytes(f: PixelFormat, width: u32) ?usize

src

The bytes width pixels take, or null if that overflows usize.

Types

enum Sample

src

The type of one sample.

Fields

u8 u8
u16 u16
f32 f32

struct Channels

src

Where each channel sits in a pixel, in samples. null for a channel the format lacks; gray formats have only y (and a), and CMYK formats none: their inks are C, M, Y, K in that order.

Fields

r: ?u2 = null
g: ?u2 = null
b: ?u2 = null
y: ?u2 = null
a: ?u2 = null

struct PixelBuffer

src

The caller's pixel memory: height rows of width pixels in format, each row starting stride bytes after the one before. Decoders write into it and never keep it.

Fields

pixels: []u8
format: PixelFormat
width: u32
height: u32
stride: usize

Bytes from the start of one row to the start of the next; at least width * format.bytesPerPixel().

Constants

pub const Error = …

src
value
error{
        /// The buffer is smaller than its dimensions and stride need, or
        /// the stride is narrower than a row.
        BufferTooSmall,
    }

Functions

pub fn init(pixels: []u8, format: PixelFormat, width: u32, height: u32) Error!PixelBuffer

src

A buffer of tightly packed rows. Fails if pixels is too short.

pub fn initStride(pixels: []u8, format: PixelFormat, width: u32, height: u32, stride: usize) Error!PixelBuffer

src

A buffer whose rows are stride bytes apart. Fails if the stride is narrower than a row or pixels is too short.

pub fn len(format: PixelFormat, width: u32, height: u32) ?usize

src

The number of bytes a tightly packed buffer of these dimensions takes, or null if it overflows usize.

pub fn check(pb: PixelBuffer) Error!void

src

Checks that every row fits in pixels. Decoders call this before writing, since the fields are public.

pub fn row(pb: PixelBuffer, y: u32) []u8

src

Row y, exactly width pixels long. Asserts y < height and a buffer that passed check.

pub fn sub(pb: PixelBuffer, x: u32, y: u32, width: u32, height: u32) PixelBuffer

src

The width by height region at (x, y), sharing this buffer's memory. Asserts the region fits.

enum PixelFormat

src
pub const PixelFormat = pixel.PixelFormat

How a pixel is laid out in memory: channel order, sample type, and whether color is premultiplied by alpha.

Fields

gray8 gray8
gray_alpha8 gray_alpha8
gray_alpha8_premul gray_alpha8_premul
rgb8 rgb8
bgr8 bgr8
rgba8 rgba8
rgba8_premul rgba8_premul
bgra8 bgra8
bgra8_premul bgra8_premul
gray16 gray16
gray_alpha16 gray_alpha16
gray_alpha16_premul gray_alpha16_premul
rgb16 rgb16
bgr16 bgr16
rgba16 rgba16
rgba16_premul rgba16_premul
bgra16 bgra16
bgra16_premul bgra16_premul
rgba_f32 rgba_f32

32-bit float samples, nominally 0 to 1, for float and HDR sources.

rgba_f32_premul rgba_f32_premul
rgb_f32 rgb_f32
gray_f32 gray_f32
cmyk8 cmyk8

Cyan, magenta, yellow, and black, each inverted (the maximum is no ink) as Adobe's CMYK JPEGs store them and libjpeg-turbo returns them, so that all-zero bytes are black here as in every other format; TIFF's and PDF's ink amounts are the maximum minus these. To color they convert naively, as libjpeg-turbo does: each of R, G, and B is ink * black / max, rounded.

cmyk16 cmyk16

Functions

pub fn sample(f: PixelFormat) Sample

src

pub fn channelCount(f: PixelFormat) usize

src

The number of samples per pixel: 1 to 4.

pub fn bytesPerSample(f: PixelFormat) usize

src

pub fn bytesPerPixel(f: PixelFormat) usize

src

pub fn hasAlpha(f: PixelFormat) bool

src

pub fn isPremultiplied(f: PixelFormat) bool

src

pub fn isGray(f: PixelFormat) bool

src

pub fn isCmyk(f: PixelFormat) bool

src

pub fn channels(f: PixelFormat) Channels

src

pub fn rowBytes(f: PixelFormat, width: u32) ?usize

src

The bytes width pixels take, or null if that overflows usize.

Types

enum Sample

src

The type of one sample.

Fields

u8 u8
u16 u16
f32 f32

struct Channels

src

Where each channel sits in a pixel, in samples. null for a channel the format lacks; gray formats have only y (and a), and CMYK formats none: their inks are C, M, Y, K in that order.

Fields

r: ?u2 = null
g: ?u2 = null
b: ?u2 = null
y: ?u2 = null
a: ?u2 = null

struct PixelBuffer

src
pub const PixelBuffer = pixel.PixelBuffer

The caller's pixel memory: height rows of width pixels in format, each row starting stride bytes after the one before. Decoders write into it and never keep it.

Fields

pixels: []u8
format: PixelFormat
width: u32
height: u32
stride: usize

Bytes from the start of one row to the start of the next; at least width * format.bytesPerPixel().

Constants

pub const Error = …

src
value
error{
        /// The buffer is smaller than its dimensions and stride need, or
        /// the stride is narrower than a row.
        BufferTooSmall,
    }

Functions

pub fn init(pixels: []u8, format: PixelFormat, width: u32, height: u32) Error!PixelBuffer

src

A buffer of tightly packed rows. Fails if pixels is too short.

pub fn initStride(pixels: []u8, format: PixelFormat, width: u32, height: u32, stride: usize) Error!PixelBuffer

src

A buffer whose rows are stride bytes apart. Fails if the stride is narrower than a row or pixels is too short.

pub fn len(format: PixelFormat, width: u32, height: u32) ?usize

src

The number of bytes a tightly packed buffer of these dimensions takes, or null if it overflows usize.

pub fn check(pb: PixelBuffer) Error!void

src

Checks that every row fits in pixels. Decoders call this before writing, since the fields are public.

pub fn row(pb: PixelBuffer, y: u32) []u8

src

Row y, exactly width pixels long. Asserts y < height and a buffer that passed check.

pub fn sub(pb: PixelBuffer, x: u32, y: u32, width: u32, height: u32) PixelBuffer

src

The width by height region at (x, y), sharing this buffer's memory. Asserts the region fits.

module convert

src

Conversion and swizzle between pixel formats.

more

Every pair of PixelFormats converts. Integer formats convert through 16-bit RGBA, and any pair with a float side through f32 RGBA. Integer results are Wuffs's pixel swizzler's on every pair it has that keeps alpha or has none to drop, with these definitions:

  • Widening an 8-bit sample multiplies by 257; narrowing a 16-bit one takes its high byte. A float sample is c / max one way and c * max rounded to nearest, clamped to 0..max, the other; NaN is 0.
  • Premultiplying is c * a / 65535 and unpremultiplying c * 65535 / a on 16-bit samples, both truncated; unpremultiplying clamps to 65535 and gives 0 where a is 0. From an 8-bit source the result keeps 8 bits (its high byte, widened again for a 16-bit destination), so 8-bit premultiplying is c * a * 257 / 65280 truncated and unpremultiplying c * 65535 / a / 256. Float conversions multiply and divide without rounding or clamping.
  • A format without alpha drops the (unpremultiplied) alpha; a source without alpha is opaque. Wuffs composites onto black there instead, the one place the integer results differ from its.
  • Gray from color is (19595 R + 38470 G + 7471 B + 32768) >> 16 on 16-bit samples (Rec. 601 luma), and 0.299 R + 0.587 G + 0.114 B with those weights in float, except that equal R, G, and B give that value exactly. Color from gray repeats the gray sample.
  • Color from CMYK, whose samples are inverted inks, is libjpeg-turbo's naive conversion at the source's depth: ink * black / max, rounded, with max 255 or 65535 (ink * black in float). CMYK from color is its naive inverse on 16-bit samples: black is m, the largest of R, G, and B, and each ink c * 65535 / m, rounded (c / m in float), 0 where m is 0, so black is all-zero bytes both ways. Alpha is dropped as for any format without it. Inks to inks pass through, not by way of color.

The pairs decoders meet most, the byte swizzles, adding and dropping alpha, premultiplying, gray to color, and 8-bit, 16-bit, and float samples to one another in the same layout, have SIMD paths that give the same bytes as the general path.

Functions

pub fn convert(dst: []u8, dst_format: PixelFormat, src: []const u8, src_format: PixelFormat, n: usize) void

src

Converts n pixels of src_format in src to dst_format in dst.

pub fn convertBuffer(dst: PixelBuffer, src: PixelBuffer) error{ SizeMismatch, BufferTooSmall }!void

src

Converts every pixel of src into dst, which must have the same dimensions. Both buffers must pass PixelBuffer.check.

Types

struct Converter

src

A conversion from one format to another, chosen once and applied to many rows. init picks a SIMD path for the pair when there is one.

Fields

dst: PixelFormat
src: PixelFormat
fast: ?Kernel
stages: Stages

Functions

pub fn init(dst: PixelFormat, src: PixelFormat) Converter

src

pub fn run(c: Converter, dst: []u8, src: []const u8, n: usize) void

src

Converts n pixels from src to dst. Asserts both hold n pixels of their format. They may be the same buffer when both formats have the same pixel size, and must not overlap otherwise.

pub fn isFast(c: Converter) bool

src

Whether run takes a SIMD path rather than the general one.

struct Config

src
pub const Config = decode.Config

The image as its header describes it, from decodeConfig.

Fields

width: u32

The canvas: the size of the pixel buffer decodeFrame writes.

height: u32
native: PixelFormat

The format that holds the source's pixels without loss and is cheapest to write: ask for it to skip conversion.

frame_count: ?u32 = null

The number of frames, or null when the header does not say, or says more than Limits.max_frames, which then counts frames as they are reached.

loop_count: ?u32 = null

How many times an animation plays (0: forever), or null for a still image.

work_len: usize = 0

Bytes of work memory decodeFrame needs.

is_opaque: bool = false

Whether the header promises every pixel is opaque.

background: ?[4]u8 = null

The background color the file names, straight RGBA, if any.

metadata: Metadata = .{}

What the decoder found before the first frame. What follows the frames updates this and background in image.Decoder.finalConfig.

struct Frame

src
pub const Frame = decode.Frame

One frame, from decodeFrame.

Fields

index: u32 = 0

0 for the first frame.

x: u32 = 0

The region of the canvas this frame wrote.

y: u32 = 0
width: u32
height: u32
duration: u64 = 0

How long to show this frame, in flicks; 0 for a still image.

disposal: Disposal = .none

What to do with this frame's region before the next frame.

blend: Blend = .src

How this frame was combined with the canvas.

is_opaque: bool = false

Whether every pixel in the region is opaque.

Types

enum Disposal

src

Fields

none none

Leave the frame on the canvas.

background background

Clear the region to transparent (or the background color).

previous previous

Restore the region to what it was before this frame.

enum Blend

src

Fields

src src

The frame replaced the region's pixels.

src_over src_over

The frame was composited over the region with its alpha.

struct Limits

src
pub const Limits = decode.Limits

Limits the caller sets before any work. A file over a limit fails with an error before the decoder writes pixels or uses work memory, so a caller that sizes buffers from Config never allocates more than these allow.

Fields

max_width: u32 = 0xFF_FFFF
max_height: u32 = 0xFF_FFFF
max_pixels: u64 = 1 << 28

The most pixels in one frame (and in the canvas).

max_frames: u32 = 1 << 16

The most frames an animated or multi-page file may have.

max_work: usize = 1 << 30

The most work memory a decoder may ask for in Config.work_len.

Constants

pub const none: Limits = …

src
value
.{
        .max_width = std.math.maxInt(u32),
        .max_height = std.math.maxInt(u32),
        .max_pixels = std.math.maxInt(u64),
        .max_frames = std.math.maxInt(u32),
        .max_work = std.math.maxInt(usize),
    }

No limits beyond what the format and usize impose.

Functions

pub fn checkSize(l: Limits, width: u32, height: u32) error{ImageTooLarge}!void

src

Fails if a width by height image is over a limit.

pub fn checkFrames(l: Limits, count: u64) error{TooManyFrames}!void

src

Fails if a file with count frames is over the frame limit.

pub fn checkWork(l: Limits, len: u64) error{WorkTooLarge}!void

src

Fails if len bytes of work memory is over the work limit.

struct DecodeOptions

src
pub const DecodeOptions = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

pub const DecodeError = decode.Error

src

The errors every decoder can return. Each format's error set is these plus its own specific causes.

struct Metadata

src
pub const Metadata = decode.Metadata

Metadata a decoder reports and never applies.

Fields

orientation: Orientation = .top_left

From EXIF (see exif.orientation) or the format's own field.

transfer: ?Transfer = null

The transfer function the file names, if any. A plain power law is gamma instead.

gamma: ?u32 = null

The file's gamma times 100,000, if any: the exponent that encoded linear light, so 45455 is 1/2.2 (PNG gAMA, a JPEG XL gamma, TGA's extension area). PNG may state it beside an sRGB transfer.

primaries: ?[8]f32 = null

CIE 1931 xy chromaticities of the red, green, and blue primaries and the white point, in that order (PNG cHRM, JPEG XL's color encoding).

intensity_target: ?f32 = null

The luminance in nits (cd/m²) that a sample of 1.0 stands for, as JPEG XL states it for HDR images.

cicp: ?Cicp = null

The ITU-T H.273 code points the file states (PNG cICP), as stored. They take precedence over an ICC profile, gamma, and the other color chunks: transfer, gamma, and primaries then come from them alone, and are null for code points they cannot name. icc is still reported beside them, though they, not it, describe the pixels.

mastering_display: ?MasteringDisplay = null

The display the image was mastered on (PNG mDCV).

content_light_level: ?ContentLightLevel = null

The brightest pixel and brightest frame average (PNG cLLI).

jpeg_reconstruction: bool = false

The file carries a JPEG XL jbrd box: the original JPEG can be rebuilt with image.jxl.JpegReconstructor.

gain_map: bool = false

The JPEG carries an HDR gain map as a second image (Ultra HDR, Adobe's gain map, or ISO 21496-1), which is neither decoded nor applied: the pixels are the base image's.

density: ?Density = null
icc: ?Blob = null

The embedded ICC profile. A cicp beside it takes precedence.

exif: ?Blob = null
xmp: ?Blob = null

Types

struct Cicp

src

ITU-T H.273's video signal type code points.

Fields

primaries: u8

ColourPrimaries: 1 is BT.709 and sRGB, 9 BT.2020, 12 Display P3.

transfer: u8

TransferCharacteristics: 13 is sRGB, 16 PQ, 18 HLG.

matrix: u8

MatrixCoefficients: 0, RGB, in PNG.

full_range: bool

Whether samples use their full range; false is narrow (video) range, such as 16 to 235 at 8 bits, which is not rescaled.

struct MasteringDisplay

src

Fields

primaries: [8]f32

CIE 1931 xy of its red, green, and blue primaries and white point, in that order, as Metadata.primaries.

min_luminance: f32

Its luminance range, in nits (cd/m²).

struct ContentLightLevel

src

In nits (cd/m²); 0 when unknown.

Fields

max_cll: f32

MaxCLL: the brightest pixel's light level.

max_fall: f32

MaxFALL: the brightest frame's average light level.

enum Orientation

src
pub const Orientation = decode.Orientation

How to rotate or flip the stored pixels for display: EXIF orientation 1 to 8, named by where the stored first row and column belong.

Fields

top_left top_left = 0
top_right top_right
bottom_right bottom_right
bottom_left bottom_left
left_top left_top
right_top right_top
right_bottom right_bottom
left_bottom left_bottom

Functions

pub fn fromExif(v: u16) ?Orientation

src

From an EXIF or TIFF orientation value, 1 to 8.

pub fn toExif(o: Orientation) u16

src

enum Transfer

src
pub const Transfer = decode.Transfer

A named transfer function, from encoded samples to linear light.

Fields

srgb srgb

IEC 61966-2-1.

linear linear
bt709 bt709

ITU-R BT.709 (and BT.601 and BT.2020's SDR curve).

dci dci

DCI-P3's power law, 1/2.6.

pq pq

SMPTE ST 2084's perceptual quantizer (BT.2100 PQ).

hlg hlg

BT.2100's hybrid log-gamma.

struct Density

src
pub const Density = decode.Density

Fields

x: u32
y: u32
unit: Unit

Types

enum Unit

src

Fields

none none

Only the aspect ratio is known.

per_inch per_inch
per_meter per_meter

struct Blob

src
pub const Blob = decode.Blob

A metadata blob: where it starts in the input, counted in bytes from the first byte the decoder read, and its length.

more

Most formats store a blob as one span of the input, and offset and len give that span (compressed if encoding says so). A format that splits it into pieces with other bytes between them, as GIF's sub-blocks do, reports the payload: len counts the payload bytes the blob sink receives, and offset is where the first of them is in the input, so the blob cannot be read back as one span from there.

Fields

kind: Kind
offset: u64
len: ?u64

The length, or null while a format that learns it only at the blob's end is still passing the blob to the sink. A Blob in Metadata always has it.

encoding: Encoding = .raw

Functions

pub fn endsAt(b: Blob, at: u64, n: usize) bool

src

Whether a piece of n bytes at at, passed with this blob, is the blob's last.

Types

enum Kind

src

Fields

icc icc
exif exif
xmp xmp

enum Encoding

src

Fields

raw raw
zlib zlib
brotli brotli

struct BlobSink

src
pub const BlobSink = decode.BlobSink

A caller's receiver for metadata blobs. The decoder calls write with each blob's bytes in order, in as many pieces as it reads them: at is the piece's offset in the blob, so a piece with at == 0 starts a blob and one for which blob.endsAt(at, bytes.len) ends it. A format that knows the length passes it with every piece; one that learns it only at the end passes blob.len null until the last piece, which may be empty. The sink copies what it wants; the bytes are gone after it returns.

Fields

context: *anyopaque
write: *const fn (context: *anyopaque, blob: Blob, at: u64, bytes: []const u8) void

Functions

pub fn put(s: BlobSink, blob: Blob, at: u64, bytes: []const u8) void

src

struct Seeker

src
pub const Seeker = decode.Seeker

A caller's way to move the input reader to any byte of the input, for formats that store offsets. The decoder still reads forward wherever it can, skipping gaps with discard, and calls seek only for data behind its position; without a seeker that data is the format's error.

more

seek(offset) must leave the reader the decoder was given so that its next byte is the input's byte offset, and drop whatever it had buffered. offset counts from the input's first byte: the reader's next byte when the decoder was made, before the decoder read anything. An offset past the input's end is not an error here: the reader then reports end of stream and the decoder Truncated. seek fails with ReadFailed only when the source cannot move.

Fields

context: *anyopaque
seek: *const fn (context: *anyopaque, offset: u64) error{ReadFailed}!void

Functions

pub fn fixed(r: *std.Io.Reader) Seeker

src

For a reader made by std.Io.Reader.fixed over the whole input, before any of it was consumed. A caller holding the file in memory gets seeking without a copy.

pub fn file(r: *std.Io.File.Reader) Seeker

src

For a file reader whose byte 0 is the input's first byte.

pub const flicks_per_second = decode.flicks_per_second

src

The flick, 1 / 705,600,000 of a second, divides every common frame rate and media timebase exactly. Frame.duration counts them.

pub const min_buffer_len = decode.min_buffer_len

src

The smallest reader buffer a decoder accepts. Decoders peek at most this many bytes at once, so std.Io.Reader.peek can serve them.

module exif

src

The one EXIF field every viewer needs: orientation. Decoders that meet EXIF (PNG eXIf, JPEG APP1, WebP EXIF, JPEG XL Exif, TIFF itself) report it in Metadata.orientation with this.

Functions

pub fn orientation(exif: []const u8) ?Orientation

src

The orientation tag's value from EXIF data: a TIFF header and IFD0, optionally after JPEG's Exif\0\0 prefix. Null when the data is malformed or IFD0 has no valid orientation. IFD0 must lie within exif; a decoder streaming EXIF can pass the blob's first few KiB, since IFD0 almost always follows the header.

pub const EncodeError = @import("encode.zig").Error

src

The errors every encoder can return. Each format's error set is these plus its own causes.

enum Format

src
pub const Format = detection.Format

Every phase-1 format. Detection knows all of them, whether or not this build has a decoder for one yet (image.Decoder.supports).

Fields

png png
jpeg jpeg
gif gif
webp webp
tiff tiff
jxl jxl
bmp bmp
ico ico
cur cur
tga tga
netpbm netpbm
wbmp wbmp
qoi qoi

Functions

pub fn namespace(f: Format) []const u8

src

The package namespace that decodes this format: cur is ico's.

pub fn detect(prefix: []const u8) ?Format

src

The format of a file starting with prefix, or null if it matches none. Formats with a signature match it exactly. BMP, ICO, and CUR also need plausible header fields. TGA has no signature and WBMP a weak one, so they are tried last, on header fields only, and can match files that are neither; a decoder still rejects what it cannot parse.

pub const detect_prefix_len = detection.prefix_len

src

How many leading bytes detect reads at most. Fewer is fine for a short file.

module Decoder

src

A decoder for any format this build supports: initDetect picks the format from the input's first bytes, and the calls are the same as each format's own Decoder. The formats come from the package root: a format namespace there (image.qoi) with a Decoder is all this needs.

Constants

pub const Error = …

src
value
blk: {
    var E = decode.Error || error{UnknownFormat};
    for (std.enums.values(Format)) |f| {
        if (supports(f)) E = E || Impl(f).Error;
    }
    break :blk E;
}

Every supported format's errors, and UnknownFormat for input that matches none.

Functions

pub fn supports(f: Format) bool

src

Whether this build decodes format.

pub fn init(f: Format, reader: *Io.Reader, options: decode.Options) error{Unsupported}!Decoder

src

A decoder for format on reader, whose buffer must hold at least image.min_buffer_len bytes.

pub fn initDetect(reader: *Io.Reader, options: decode.Options) error{ ReadFailed, UnknownFormat, Unsupported }!Decoder

src

A decoder for whatever format reader's input is, found by image.detect from its first bytes, which stay in the reader.

pub fn format(d: *const Decoder) Format

src

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

See the format's decodeConfig.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

See the format's decodeFrame.

pub fn decodeFrameConfig(d: *Decoder) Error!?decode.Frame

src

The frame the next decodeFrame call returns, read before it draws anything, or null where that call returns null; see the format's decodeFrameConfig. A format without one has at most one frame, and its frame is the whole canvas, as its decodeFrame returns it; a format that may have more frames and lacks one is Unsupported here.

pub fn finalConfig(d: *Decoder) ?decode.Config

src

The config decodeConfig returned, updated with what the format found after its frames, such as TGA's footer or a PNG's chunks after its image data: null until decodeFrame has returned null. A format reports those with an optional applyTrailer(*const Self, *Config) void, which sets the fields it found late and leaves the rest; without one this is the config as decodeConfig returned it.

module bmp

src

BMP, the Windows and OS/2 bitmap: decode, and encode as 24-bit, 32-bit with alpha, or 8-bit with a color table.

Constants

pub const EncodeError = encoder.Error

src

Functions

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: Options, work: []u8) Error!void

src

Writes src as a BMP file.

pub fn workLen(options: Options, width: u32, height: u32) ?usize

src

BMP needs no work memory: 0, or null when the image is too large for the format (a side over 2^31 - 1 pixels, or a file of 4 GiB or more).

Types

module Decoder

src

A streaming BMP decoder: reads from a std.Io.Reader, writes any PixelFormat, needs no work memory, and allocates nothing.

more

Every header version (OS/2 1.x and 2.x, and Windows 3 through 5), 1-, 2-, 4-, 8-, 16-, 24-, and 32-bit pixels, RLE4 and RLE8, bitfields with or without alpha, and top-down and bottom-up rows. A JPEG or PNG stream in place of the pixels is reported (error.EmbeddedJpeg, error.EmbeddedPng) with the reader at its first byte, for the caller to hand to a JPEG or PNG decoder. dib.zig decides the cases the format leaves open. The color table is the bytes between the info header and the pixels, as the pixel offset says, up to 256 entries.

Constants

pub const Error = …

src
value
dib.Error || error{
    /// The pixels are a JPEG stream (`BI_JPEG`). `decodeConfig` leaves the
    /// reader at its first byte, and `embeddedLen` says how long it is.
    EmbeddedJpeg,
    /// The pixels are a PNG stream (`BI_PNG`). `decodeConfig` leaves the
    /// reader at its first byte, and `embeddedLen` says how long it is.
    EmbeddedPng,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame, and stops after the last row.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the file and info headers. The native format is bgr8, or bgra8 when the pixels have an alpha mask or are RLE (whose skipped pixels are transparent). Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the image into dst, which must be the image's size, in any format. Returns null once the image is decoded. work is unused: BMP needs no work memory. With a blob_sink, an ICC profile stored after the pixels is read and passed on too.

pub fn embeddedLen(d: *const Decoder) u32

src

The length of the JPEG or PNG stream after error.EmbeddedJpeg or error.EmbeddedPng: the header's image size, which may be 0.

Types

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

struct EncodeOptions

src
pub const EncodeOptions = encoder.Options

Fields

format: Format = .auto

What the file stores.

Types

enum Format

src

Fields

auto auto

indexed8 for gray pixels without alpha, bgra32 for pixels with alpha, and bgr24 for the rest.

bgr24 bgr24

24-bit pixels in a BITMAPINFOHEADER file; alpha is dropped.

bgra32 bgra32

32-bit pixels with straight alpha: BI_BITFIELDS in a BITMAPV4HEADER, which is how readers learn there is alpha.

indexed8 indexed8

8-bit indices into a color table of the image's colors, alpha dropped: a gray ramp for gray pixels, and otherwise every distinct color, at most 256 (error.TooManyColors).

module ico

src

ICO and CUR, Windows icons and cursors: decode every entry, with BMP or PNG data, and encode BMP and PNG entries. PNG entries decode through image.png when the build has it.

Constants

pub const Decoder = decoder.Generic(if (@hasDecl(image, "png")) image.png.Decoder else void)

src

pub const max_entries = decoder.max_entries

src

The most entries a file may have.

pub const EncodeError = encoder.Error

src

Functions

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: Options, work: []u8) Error!void

src

Writes src as a one-entry ICO or CUR file.

pub fn encodeAll(w: *Io.Writer, images: []const Image, options: Options, work: []u8) Error!void

src

Writes images as the entries of one ICO or CUR file, in order. work holds at least workLen for each image with its payload: the largest PNG entry's.

pub fn workLen(options: Options, width: u32, height: u32) ?usize

src

The work memory for an image with options.payload: none for a BMP entry, and png.workLen with the default options for a PNG entry (about 850 KiB at 256 by 256). Null when a side is 0 or over 256.

Types

struct Entry

src
pub const Entry = decoder.Entry

One directory entry.

Fields

width: u16

The size the directory gives, 1 to 256. The entry's own header decides the size it decodes to.

height: u16
colors: u8

Colors in the entry's color table: 0 for none or 256 or more.

planes: u16

ICO: color planes. CUR: the hotspot's x.

bits: u16

ICO: bits per pixel. CUR: the hotspot's y.

size: u32

The entry's data: its length and its offset in the file.

offset: u32

struct EncodeOptions

src
pub const EncodeOptions = encoder.Options

Fields

cursor: bool = false

Write a CUR, whose entries have hotspots, rather than an ICO.

hotspot: [2]u16 = .{ 0, 0 }

encode's image's hotspot, for a cursor.

payload: Payload = .auto

encode's image's payload; encodeAll takes each image's.

struct Image

src
pub const Image = encoder.Image

One image for encodeAll.

Fields

pixels: PixelBuffer
hotspot: [2]u16 = .{ 0, 0 }

The hotspot, for a cursor.

payload: Payload = .auto

enum Payload

src
pub const Payload = encoder.Payload

How an entry stores its pixels.

Fields

auto auto

PNG for a 256 by 256 image, BMP otherwise, as Windows' own icons are made.

bmp bmp

A 32-bit BMP and its mask, which every reader takes.

png png

A PNG of the image's own channels at 8 bits, reduced to the smallest color type that holds them, which Windows Vista and later read.

module gif

src

GIF (GIF87a and GIF89a, with the NETSCAPE2.0 loop count): decode, still and animated; encode GIF89a stills and animations from any pixel format, quantizing frames with more than 256 colors.

Constants

pub const EncodeError = encoder.EncodeError

src

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode and encodeAnimation need for a width by height canvas, or null when GIF cannot store it.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a GIF file.

pub fn encodeAnimation( w: *Io.Writer, width: u32, height: u32, frames: []const AnimationFrame, options: EncodeOptions, work: []u8, ) EncodeError!void

src

Writes frames as an animation on a width by height canvas.

Types

module Decoder

src

A streaming GIF decoder: reads from a std.Io.Reader, writes any PixelFormat, and allocates nothing. It needs Config.work_len bytes of work memory (about 68 KiB): the LZW table, a buffer of decoded palette indices, a buffer of compressed data, and the palette in the destination's format. Nothing scales with the image.

more

Format: GIF87a and GIF89a (W3C, 1987 and 1990), with the NETSCAPE2.0 (or ANIMEXTS1.0) application extension's loop count. Global and local color tables, interlacing, and the graphic control extension's transparent index, delay, and disposal. ICC profiles (ICCRGBG1012) and XMP packets (XMP DataXMP) go to Options.blob_sink and Config.metadata, or, after the first frame, applyTrailer. Comments, plain text, and other application extensions are skipped.

Frames follow the APNG model: decodeFrame writes each frame into its region of the caller's canvas, which must hold the previous frame with its disposal applied. The first frame clears the canvas outside its region to transparent black and writes its transparent pixels as transparent black (Frame.blend is src); a later frame with a transparent index leaves the canvas under those pixels alone (src_over). Disposal is the caller's: Frame.disposal says what to do with the region before the next frame, and decodeFrameConfig reports the next frame before it is drawn, so a caller can save the region that restore-to-previous needs.

Where the specification leaves room, this decoder does what Wuffs does by default: the canvas grows to hold the first frame, later frames are clipped to it, a frame's LZW data must hold exactly its pixels (unless Options.ignore_too_much_data lets it hold more), an index past the color table (or with no color table) is opaque black, the last of several graphic control extensions wins, and a byte that starts no block ends the image as the trailer does. A file cut short is Truncated, even after its last frame, where the trailer should be.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// A graphic control extension is not one block of 4 bytes.
    BadBlock,
    /// The minimum code size is past 8, or a code names an LZW table
    /// entry not yet defined.
    BadLzw,
    /// The LZW data ends before the frame's last pixel.
    NotEnoughData,
    /// The LZW data holds more pixels than the frame (not with
    /// `Options.ignore_too_much_data`).
    TooMuchData,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame, and stops after the trailer.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the header, the global color table, and the blocks up to the first frame's color table. The native format is RGBA8: an animation's canvas can be transparent wherever a frame does not cover it. frame_count is null (GIF does not say), and loop_count is the NETSCAPE2.0 count as a number of plays (the count plus one, or 0 for forever) when one comes before the first frame, and 1 otherwise, as browsers play such a file once. Calling it again returns the same config.

pub fn applyTrailer(d: *const Decoder, config: *decode.Config) void

src

Sets the ICC profile and XMP packet found after the first frame, when none came before it, for image.Decoder.finalConfig.

pub fn decodeFrameConfig(d: *Decoder) Error!?decode.Frame

src

Reads up to the next frame's pixels and returns the frame that decodeFrame will decode next, without drawing it, or null after the last frame. A caller saves the region here for a frame whose disposal is previous.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the next frame into its region of dst, which must be the canvas's size, in any format, using work[0..work_len]. Returns null after the last frame, once the trailer is read.

Types

struct Options

src

Fields

limits: decode.Limits = .{}
blob_sink: ?decode.BlobSink = null
ignore_too_much_data: bool = false

Accept a frame whose LZW data holds more pixels than the frame: the rest are dropped, and once the frame is whole, a bad code ends its data instead of failing. This is what Wuffs's IGNORE_TOO_MUCH_PIXEL_DATA quirk does (giflib drops the rest too). Off by default: such a frame is TooMuchData.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

quantizer: Quantizer = .wu

How a frame with more than 256 colors gets its palette.

refine: u8 = 0

k-means passes over the quantizer's palette.

dither: Dither = .floyd_steinberg

How a quantized frame's pixels map to its palette.

interlace: bool = false
loop_count: u32 = 0

An animation's play count: 0 plays forever.

crop: bool = true

Store each frame of an animation as only what it changes.

struct AnimationFrame

src
pub const AnimationFrame = encoder.AnimationFrame

One frame of an animation.

Fields

pixels: PixelBuffer

The frame's pixels, in any format, the size of its region.

x: u32 = 0

The region's top left corner on the canvas.

y: u32 = 0
duration: u64 = 0

How long to show the frame, in flicks (image.flicks_per_second); stored in hundredths of a second, rounded, at most 65535.

disposal: decode.Frame.Disposal = .none

enum Quantizer

src
pub const Quantizer = encoder.Quantizer

Fields

wu wu
median_cut median_cut
octree octree

enum Dither

src
pub const Dither = encoder.Dither

Fields

none none
floyd_steinberg floyd_steinberg

Floyd-Steinberg error diffusion, serpentine.

module png

src

PNG and APNG (the PNG specification, third edition): decode, and encode with filter selection, palette and gray reduction, and APNG frames.

Constants

pub const EncodeError = encoder.EncodeError

src

Functions

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a PNG file. The bytes depend only on src's pixels, options, and work.len, not on what work held before.

pub fn encodeAnimation( w: *Io.Writer, width: u32, height: u32, frames: []const AnimationFrame, options: EncodeOptions, work: []u8, ) EncodeError!void

src

Writes frames as an APNG on a width by height canvas. The first frame is also the default image, so it must be the whole canvas. As with encode, the bytes do not depend on what work held before.

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode and encodeAnimation need for a width by height canvas, or null when PNG cannot store it.

Types

module Decoder

src

A streaming PNG and APNG decoder: reads from a std.Io.Reader, writes any PixelFormat, and allocates nothing. It needs Config.work_len bytes of work memory: the 64 KiB inflate window, an 8 KiB staging buffer for the image data, and two rows.

more

Format: the PNG specification, third edition (W3C, 2025), which includes APNG. Every color type, bit depth, and Adam7 interlacing; tRNS becomes an alpha channel in the native format. gAMA, cHRM, sRGB, cICP, mDCV, cLLI, pHYs, iCCP, eXIf, and bKGD are reported in Config and never applied; iCCP and eXIf bytes go to the blob sink as they pass. cICP takes precedence over iCCP, sRGB, gAMA, and cHRM, as section 4.3 orders them.

Strict, as Wuffs is: the CRC-32 of every critical chunk (IHDR, PLTE, IDAT, IEND) is checked, and so is the image data's Adler-32, unless Options.ignore_checksums is set. Ancillary chunks' CRCs are not checked, as in Wuffs; libpng and libspng accept a bad one too. The image data must decompress to exactly the rows the image needs, with nothing after the zlib stream in its chunks; an interlaced frame one row tall is the exception, as in Wuffs: data after its last row is skipped. Chunks that shape the pixels (IHDR, PLTE, tRNS, IDAT, IEND, acTL, fcTL, fdAT) must follow the specification; a chunk that cannot change the pixels (a metadata chunk with a malformed body, a tRNS beside an alpha channel) is ignored, as the specification allows, and the first of a duplicate wins. An unknown critical chunk is Unsupported. An out-of-range palette index is opaque black, as the specification requires.

APNG: the frames are the animation's. A default image outside the animation (no fcTL before IDAT) is skipped, as APNG decoders are to do. decodeFrame writes each frame into its region of the caller's canvas: blend-over frames are composited onto what the canvas holds, and the first frame clears the canvas outside its region to transparent black. Disposal is the caller's: Frame.disposal says what to do with the region before the next call. A still image's IEND is read by the second decodeFrame, which returns null.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// A critical chunk's CRC-32 does not match its type and data (not
    /// with `Options.ignore_checksums`).
    BadCrc,
    /// A chunk's length, contents, or position breaks the specification:
    /// a missing or misplaced PLTE or IDAT, a malformed
    /// tRNS, acTL, fcTL, or fdAT, out-of-order sequence numbers, or a
    /// frame count that disagrees with acTL.
    BadChunk,
    /// A row's filter type is not 0 to 4.
    BadFilter,
    /// The image data is not a valid zlib stream, or names a preset
    /// dictionary.
    BadZlib,
    /// The image data's Adler-32 does not match (not with
    /// `Options.ignore_checksums`).
    BadChecksum,
    /// The image data ends before the frame's last row.
    NotEnoughData,
    /// The image data holds more than the frame's rows, or its chunks hold
    /// bytes after the zlib stream. Not for an interlaced frame one row
    /// tall, whose data past its last row is skipped, as in Wuffs.
    TooMuchData,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame, and stops after IEND.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the chunks before the first IDAT. The native format holds the samples at their depth (8 bits for depths below 8, 16 bits in the machine's byte order for 16), as gray, gray and alpha, RGB, or RGBA; palette images are RGB. tRNS adds alpha, and so does APNG, whose canvas can be cleared to transparent black. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the next frame into its region of dst, which must be the canvas's size, in any format, using work[0..work_len]. Returns null after the last frame, once IEND is read.

pub fn decodeFrameConfig(d: *Decoder) Error!?decode.Frame

src

Reads up to the next frame's pixels and returns the frame decodeFrame will decode next, without drawing it, or null after the last frame. A caller saves the region here for a frame whose disposal is previous.

pub fn applyTrailer(d: *const Decoder, config: *decode.Config) void

src

Sets in config an eXIf found after the image data, and the orientation it gives. image.Decoder.finalConfig calls it once the frames end. The other metadata chunks must come before the image data and are ignored after it.

pub fn maxWorkLen(width: u32) ?usize

src

The work memory any PNG no wider than width needs: Config.work_len for 16-bit RGBA, the widest pixel. For a container that must state the work memory before it reaches a PNG's header (ICO).

Types

struct Options

src

Fields

limits: decode.Limits = .{}
blob_sink: ?decode.BlobSink = null
ignore_checksums: bool = false

Skip the CRC-32 of critical chunks and the image data's Adler-32, as Wuffs's IGNORE_CHECKSUM quirk does, so a file whose only fault is a checksum decodes. Off by default.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

effort: Effort = .default
filter: ?Filter = null

One filter for every row that is filtered, instead of the effort's.

reduce: bool = true

Write the smallest color type and bit depth that hold the pixels exactly; otherwise the base format's.

max_depth: MaxDepth = .@"16"

The most bits a sample may have: .@"8" stores 16-bit and float sources at 8 bits, converting each row as it is read (no more work memory), and reduction still picks the smallest type that holds those 8-bit samples. ICO's PNG entries use it.

gamma: ?u32 = null

gAMA: the image's gamma times 100,000.

primaries: ?[8]f32 = null

cHRM: red, green, blue, and white xy, as Metadata.primaries reports them, each stored times 100,000, rounded.

srgb: ?RenderingIntent = null

sRGB; not with icc.

icc: ?Icc = null

iCCP; not with srgb.

cicp: ?decode.Metadata.Cicp = null

cICP: ITU-T H.273 code points, as Metadata.cicp reports them; the matrix must be 0. Readers that know it ignore iCCP, sRGB, gAMA, and cHRM.

mastering_display: ?decode.Metadata.MasteringDisplay = null

mDCV: chromaticities stored times 50,000 and luminances times 10,000, rounded.

content_light_level: ?decode.Metadata.ContentLightLevel = null

cLLI: light levels stored times 10,000, rounded.

exif: ?[]const u8 = null

eXIf: an EXIF profile, starting with its TIFF header.

density: ?decode.Density = null

pHYs: pixels per meter, or only the aspect ratio with .none. Pixels per inch are stored per meter, rounded to the nearest.

loop_count: u32 = 0

An APNG's play count: 0 plays forever.

enum MaxDepth

src
pub const MaxDepth = encoder.MaxDepth

Fields

@"8" @"8"
@"16" @"16"

struct AnimationFrame

src
pub const AnimationFrame = encoder.AnimationFrame

One frame of an APNG.

Fields

pixels: PixelBuffer

The frame's pixels, in any format, the size of its region.

x: u32 = 0

The region's top left corner on the canvas.

y: u32 = 0
duration: u64 = 0

How long to show the frame, in flicks (image.flicks_per_second); stored exactly when it is a fraction of a second with a numerator and denominator below 65536, and as the nearest such fraction otherwise.

disposal: decode.Frame.Disposal = .none
blend: decode.Frame.Blend = .src

module jpeg

src

JPEG (ITU T.81, with T.871's JFIF and Adobe's APP14): decode, and encode baseline or progressive.

Constants

pub const EncodeError = encoder.EncodeError

src

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs for a width by height image: a row of the source converted, the samples of one MCU row, and the coefficients of one MCU row or, for optimized tables or progressive scans, of the whole image, two bytes per sample of each component with its blocks padded to whole MCUs. It assumes a color source, which needs at least what a gray one does. Null if the image is too large for JPEG or for usize.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a JPEG file to w. work holds at least workLen(options, src.width, src.height) bytes.

Types

module Decoder

src

A streaming JPEG decoder: reads from a std.Io.Reader, writes any PixelFormat, and allocates nothing. It needs Config.work_len bytes of work memory: the entropy decoder's tables, a few rows of each component, and, for progressive and multi-scan files, every component's coefficients (or, lossless, samples).

more

Format: ITU T.81 (JPEG), with T.871 (JFIF) and Adobe's APP14 for the color transform. Sequential and progressive DCT images with 8- or 12-bit samples, Huffman- or arithmetic-coded; lossless images (process 14, Huffman-coded) of 2 to 16 bits; every sampling factor libjpeg-turbo accepts, restart intervals, grayscale, gray with alpha (two components, unconverted, as libjpeg reads them), YCbCr, RGB, CMYK, and YCCK; and decoding DCT images at 1/2, 1/4, or 1/8 size (Options.scale). The hierarchical processes and lossless arithmetic coding, which libjpeg-turbo does not decode either, are Unsupported.

The pixels are libjpeg-turbo's with its default settings, bit for bit: its accurate integer IDCT, its "fancy" upsampling, and its YCbCr to RGB. CMYK and YCCK images decode to RGB by libjpeg-turbo's naive conversion, or to their stored inks with Options.cmyk = .raw. Samples of other precisions than 8 bits are scaled to the native format, rounded: 16-bit past 8 bits, 8-bit below.

Strict, as libjpeg-turbo is when it treats warnings as errors: a truncated file, a marker segment of the wrong length, an undefined Huffman code, entropy-coded data that ends before its scan or restart interval does, a wrong restart marker, or an inconsistent progression is an error. Bytes that are not a marker between segments are skipped, as the reference skips them. decodeFrame reads through EOI.

Metadata is reported in Config and never applied: JFIF density, the EXIF orientation, and the ICC profile (reassembled from its APP2 segments), EXIF, and XMP blobs, which go to the blob sink as they pass. Metadata.gain_map flags an HDR gain map (Ultra HDR, Adobe's, or ISO 21496-1): an MPF APP2 segment, which locates the second image, and either the gain map namespace in the XMP or ISO 21496-1's APP2 segment. The gain map image after EOI is never read.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// A marker that is not allowed where it appears, an unknown marker,
    /// or a marker segment whose length or contents break the
    /// specification.
    BadMarker,
    /// A DHT table with more codes than its lengths allow, or a DC symbol
    /// past 15.
    BadHuffmanTable,
    /// A code in the entropy-coded data that its table does not have, or a
    /// refinement coefficient whose size is not 1.
    BadHuffmanCode,
    /// A scan names a component, table, or band the frame does not have:
    /// an unknown component, a component twice, a missing quantization or
    /// Huffman table, more than 10 blocks per MCU, or a spectral band or
    /// successive approximation the progressive process does not allow;
    /// or a lossless image with a component no scan covers.
    BadScan,
    /// A progressive scan out of order: an AC scan before the component's
    /// DC scan, or a refinement whose bit position does not follow the
    /// previous scan of its coefficients.
    BadProgression,
    /// A progressive DC coefficient past 32 bits.
    BadCoefficient,
    /// A scan's entropy-coded data ends before its last MCU, or before
    /// the end of a restart interval.
    NotEnoughData,
    /// A restart interval ends at a marker other than the expected RSTn.
    BadRestart,
    /// Arithmetic-coded data decodes to a value T.81 does not allow: a
    /// run of zero coefficients past the end of the band, or a magnitude
    /// past 15 bits.
    BadArithmeticCode,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame, and stops after EOI.

pub fn keptTables(d: *const Decoder) Tables

src

The tables defined so far, for Options.prior of the next stream: after decodeFrame, all of this stream's.

pub fn frameParams(d: *const Decoder) FrameParams

src

The frame header decodeConfig read, as a container would state it: components, sampling, precision, and whether the stream is lossless or keeps every coefficient (progressive, or its first scan codes fewer than all the components).

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the markers through the first scan's header. The native format is gray8 for one component, gray_alpha8 for two, and rgb8 for three or four (cmyk8 with Options.cmyk = .raw), or the 16-bit formats for samples past 8 bits. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the image into dst, which must be the canvas's size (or, with Options.crop, no larger), in any format, reading through EOI. Returns null once the image is decoded.

pub fn workLen(params: FrameParams, options: Options) Error!usize

src

The work memory that decodeFrame needs for a stream whose frame header matches params, decoded with options: what decodeConfig would state, without reading the stream. A stream whose frame differs may need more; decodeFrame checks, and returns error.WorkTooSmall.

Types

struct Options

src

Fields

limits: decode.Limits = .{}
blob_sink: ?decode.BlobSink = null
scale: Scale = .full

Decode at a fraction of the size, in the DCT domain, as libjpeg-turbo's scale_num / scale_denom does: the canvas is the image's size times the scale, rounded up. Lossless images, which have no DCT, ignore it, as in libjpeg-turbo.

tables: ?[]const u8 = null

A table-specification stream (SOI, segments, EOI) whose quantization and Huffman tables apply as if they came before the image's own: TIFF's JPEGTables, for its abbreviated image streams. It is read as libjpeg reads a header: SOFn is checked and dropped, DNL skipped, RSTn and TEM ignored, and SOS refused; DAC and DRI are read, but the image stream's SOI resets them, as in libjpeg.

prior: ?*const Tables = null

Tables an earlier stream left (Decoder.keptTables), applied before tables: libjpeg keeps a stream's quantization and Huffman tables for the next one it reads, as libtiff relies on across a TIFF's strips and tiles. A caller that carries them reads JPEGTables once, into the first stream.

color: ColorHint = .auto

How to read a three- or four-component image's color: from its markers and component IDs, as libjpeg-turbo guesses (auto), or as the caller knows it, as TIFF's photometric interpretation says.

cmyk: Cmyk = .rgb

What a CMYK or YCCK image decodes to.

crop: bool = false

Whether decodeFrame takes a destination smaller than the frame, writing the frame's top-left dst.width × dst.height pixels and decoding the rest without writing it, as for TIFF's edge tiles, which are coded whole but lie partly outside the image.

struct Tables

src

The quantization and Huffman tables a stream defined, with those it inherited.

Fields

quant: [4][64]u16 = undefined
quant_set: [4]bool = @splat(false)
dc_spec: [4]huffman.Spec = undefined
ac_spec: [4]huffman.Spec = undefined
dc_set: [4]bool = @splat(false)
ac_set: [4]bool = @splat(false)

enum Scale

src
pub const Scale = enum(u2)

Fields

full full
half half
quarter quarter
eighth eighth

enum ColorHint

src

Fields

auto auto
none none

RGB or CMYK, without a color transform.

ycc ycc

YCbCr or YCCK.

enum Cmyk

src

Fields

rgb rgb

RGB by libjpeg-turbo's naive conversion (each channel is the ink's stored sample times black's, over the maximum); native is RGB.

raw raw

The inks as stored, inverted as Adobe stores them (0 is full ink), and YCCK's converted from YCbCr as libjpeg-turbo converts them. Native is cmyk8 (cmyk16 past 8 bits, scaled), and other formats convert from it as image.convert does.

struct FrameParams

src

A frame as a container states it before its JPEG stream, as TIFF's IFD does: what workLen needs.

Fields

width: u32
height: u32
components: u8

1 (gray), 2 (gray and alpha, as TIFF writes them), 3, or 4.

sampling: [4]Sampling = @splat(.{})

Each component's sampling factors, 1 to 4.

precision: u8 = 8

8 or 12 bits, or 2 to 16 for lossless.

lossless: bool = false
multi_scan: bool = true

Whether to provide for a progressive stream, or one that codes its components in separate scans, which keep every coefficient until the last scan. Without it the bound covers single-scan streams only, and decodeFrame returns error.WorkTooSmall for the rest.

Types

struct Sampling

src

Fields

h: u8 = 1
v: u8 = 1

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

quality: u8 = 75

libjpeg's quality, 1 to 100: T.81 K.1's tables scaled by 5000/q below 50 and by 200 - 2q from 50, each value kept within 1 to 255. 0 counts as 1, and above 100 as 100.

subsampling: Subsampling = .@"4:2:0"

The chroma resolution of a color source; gray sources have none.

progressive: bool = false

Progressive scans, by libjpeg's default script, with optimized Huffman tables for each.

optimize: bool = false

Huffman tables made for the image (T.81 K.2) rather than the standard ones of K.3; always so for progressive files.

exif: ?[]const u8 = null

An EXIF block to write in APP1, from its TIFF header on (what follows "Exif\x00\x00"), at most 65,527 bytes.

icc: ?[]const u8 = null

An ICC profile to write in APP2 segments of up to 65,519 bytes, at most 255 of them.

enum Subsampling

src
pub const Subsampling = encoder.Subsampling

Fields

@"4:4:4" @"4:4:4"

Chroma at full resolution.

@"4:2:2" @"4:2:2"

Chroma at half the width.

@"4:2:0" @"4:2:0"

Chroma at half the width and half the height.

module qoi

src

QOI, the Quite OK Image format (qoiformat.org): decode and encode.

Constants

pub const EncodeError = encoder.EncodeError

src

The errors every encoder can return. Each format's error set is these plus its own causes.

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

QOI needs no work memory.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a QOI file to w.

Types

module Decoder

src

A streaming QOI decoder: reads from a std.Io.Reader, writes any PixelFormat, needs no work memory, and allocates nothing.

Format: the QOI specification, version 1.0 (qoiformat.org). Every decoded pixel goes into the index, runs and index chunks included, as the specification says. The decoder is strict where the specification is silent: the stream must end with its 8-byte end marker, and a run may not go past the last pixel.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// The stream does not end with the end marker, seven zeros and a one.
    BadFooter,
    /// A run goes past the last pixel.
    RunPastEnd,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame, and stops after the end marker.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the 14-byte header. The native format is rgb8 for a three-channel file and rgba8 for a four-channel one. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the image into dst, which must be the image's size, in any format. Returns null once the image is decoded. work is unused: QOI needs no work memory.

Types

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

transfer: Transfer = .srgb

The header's colorspace byte: 1 for linear (all channels linear), and 0, sRGB with linear alpha, for any other transfer, which QOI cannot name. It changes nothing in the pixels.

module tga

src

TGA (Truevision TGA, Targa), version 2.0 and the original format: decode every image type, encode true-color and gray, uncompressed or run-length encoded.

Constants

pub const EncodeError = encoder.EncodeError

src

The errors every encoder can return. Each format's error set is these plus its own causes.

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs for a width by height image: a row of pixels as the file stores them, and for run-length encoding, the row's packets. Null if the image is too large for TGA.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a TGA file to w, converting its pixels to what the file stores. work holds at least workLen(options, src.width, src.height) bytes.

Types

module Decoder

src

A streaming TGA decoder: reads from a std.Io.Reader, writes any PixelFormat, and allocates nothing. A color-mapped image keeps its color map in the caller's work memory (Config.work_len, 4 bytes an entry); every other image needs none.

more

Format: the Truevision TGA File Format Specification, version 2.0. Every image type the specification defines: color-mapped (1, 9) with 8- or 16-bit indices and 15-, 16-, 24-, or 32-bit entries, true-color (2, 10) at 15, 16, 24, and 32 bits, gray (3, 11) at 8 bits and 16 (gray and alpha), run-length encoded or not, in any of the four origins, and type 0, which has no image (no frames). Where the specification leaves a choice:

  • 32-bit pixels and color-map entries always carry alpha, whatever the descriptor's attribute-bit count says, as every reader we compare with does; 16-bit pixels use their top bit as alpha only when the descriptor names one attribute bit; 15- and 16-bit color-map entries are opaque, as the specification says of their 16th bit. Five-bit channels widen by bit replication.
  • A color map's first entry index offsets the indices: pixel value i is entry i - first. An index outside the map is opaque black, as in Wuffs.
  • Run-length packets may run from one scan line into the next (the specification says they should not, and older writers do), but not past the last pixel (RunPastEnd).
  • The descriptor's interleaving bits (7-6), the screen origin, and the color-map fields of an image without a color map are ignored; a color map in a true-color or gray file is skipped.

The TGA 2.0 footer and extension area follow the pixels, so they cannot shape Config: the decodeFrame call after the image reads the rest of the input and trailer reports what it found. Reading forward only, the decoder finds an extension area that starts right after the image data or ends right before the footer, the two places writers put it.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// A run-length packet goes past the last pixel.
    RunPastEnd,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the 18-byte header. The native format is bgr8 or bgra8 for color, gray8 or gray_alpha8 for gray. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the image into dst, which must be the image's size, in any format, using work[0..Config.work_len]. The call after the image (or the first, for type 0) reads the rest of the input for the footer, returns null, and leaves what it found in trailer.

pub fn trailer(d: *const Decoder) ?Trailer

src

The footer and extension area, once the decodeFrame call that returns null has read them; null before.

pub fn applyTrailer(d: *const Decoder, config: *decode.Config) void

src

Sets in config what the extension area gives: the gamma and the pixel aspect ratio in its metadata, and the key color as its background. image.Decoder.finalConfig calls it once the frames end; the attributes type is only in trailer.

Types

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

struct Trailer

src

What follows the image: the TGA 2.0 footer and the extension area it points to.

Fields

footer: bool = false

Whether the input ends with the TGA 2.0 footer.

extension_offset: u32 = 0

The footer's offsets of the extension area and the developer directory, from the start of the file; 0 when there is none.

developer_offset: u32 = 0
extension: ?Extension = null

The extension area's fields that describe the image, when the footer names one where this decoder can read it (see the top of this file).

struct Extension

src

The extension area's fields that describe the image. Its text fields, time stamps, postage stamp, and tables are skipped.

Fields

metadata: decode.Metadata = .{}

gamma from the gamma value, as PNG's gAMA would store it (the file's 2.2 is 45455), and density from the pixel aspect ratio, with no unit.

background: ?[4]u8 = null

The key color, straight RGBA, unless it is zero (unset).

alpha: ?Alpha = null

What the alpha channel holds, if the attributes type says.

Types

enum Alpha

src
pub const Alpha = enum(u8)

Fields

none none = 0

No alpha data.

ignore ignore = 1

Undefined data that can be ignored.

retain retain = 2

Undefined data that should be retained.

straight straight = 3

Alpha, straight.

premultiplied premultiplied = 4

Alpha, with the color premultiplied by it.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

rle: bool = true

Run-length encode the pixels; otherwise store them as they are.

module netpbm

src

Netpbm (netpbm.sourceforge.net/doc): PBM, PGM, and PPM, plain and raw; PAM; and PFM, decode and encode. A raw file holding several images decodes them as frames.

Constants

pub const EncodeError = enc.EncodeError

src

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs: none.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src to w as one Netpbm image.

Types

module Decoder

src

A streaming Netpbm decoder: PBM, PGM, and PPM, plain and raw; PAM; and PFM. It reads from a std.Io.Reader, writes any PixelFormat, needs no work memory, and allocates nothing.

more

Formats: the Netpbm specifications (netpbm.sourceforge.net/doc: pbm, pgm, ppm, pam, and pfm). The native pixel format is 8-bit for a maxval up to 255 and 16-bit above it, gray, gray and alpha, RGB, or RGBA as the file stores; PBM is gray8, and PFM is rgba_f32. A sample v with maxval m is the fraction v / m of full scale, so it becomes v * 255 / m (or v * 65535 / m) rounded to nearest; maxval 255 and 65535 keep the samples as they are.

How strict the decoder is, where the specifications leave room:

  • Header numbers are ASCII decimal, separated by at least one whitespace character (space, tab, CR, LF, VT, FF). A comment runs from # to the next CR or LF, which stays and counts as whitespace, so 255#c\n ends a header. Exactly one whitespace character ends a PBM, PGM, PPM, or PFM header. A zero width, height, depth, or maxval, a maxval over 65535, or anything else out of place is BadHeader; a width or height over 2^32 - 1 is ImageTooLarge.
  • PAM: P7 and a newline, then lines of one keyword and its value; blank lines and lines starting with # (after blanks) are ignored, and blanks (whitespace but LF, so a CR too) may end a line. WIDTH, HEIGHT, DEPTH, MAXVAL, and ENDHDR must each appear once, and an unknown keyword or an extra token on a line is BadHeader. The tuple types BLACKANDWHITE and GRAYSCALE (read the same way, as gray scaled by maxval), RGB, and their _ALPHA forms are read from the first one to four planes, and further planes are skipped, as the PAM specification recommends; a depth too small for the type is BadHeader. Without a tuple type, depth 1 to 4 reads as gray, gray and alpha, RGB, and RGBA; any other tuple type, or no tuple type with a larger depth, is Unsupported.
  • PFM: PF (color) or Pf (gray), the width, the height, and the scale, a nonzero decimal number whose sign gives the byte order (negative is little endian); the scale's magnitude names units and is not applied. Rows are stored bottom to top and written top to bottom.
  • A sample above maxval is SampleOutOfRange.
  • Plain rasters (P1, P2, P3) are read leniently, as their specifications ask: any whitespace between samples, and comments, as libnetpbm accepts them. A sample must end with whitespace, a comment, or the end of the input, and anything after the last sample must start with whitespace or a comment; otherwise it is BadRaster. The decoder reads nothing past the last sample.
  • Frames: a raw PBM, PGM, PPM, or PAM file is a sequence of images, each a frame. Whitespace between images and after the last is skipped (as libnetpbm skips it between plain images); then the input must end or hold another image with the same magic number, size, and native format (FrameMismatch otherwise). Config.frame_count is null for these, since only the end of the input tells. Plain files and PFM hold one image, and the decoder stops after it.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// A sample is greater than the header's maxval.
    SampleOutOfRange,
    /// A plain raster holds something other than samples, whitespace, and
    /// comments, or a sample runs into the next character.
    BadRaster,
    /// An image after the first has another magic number, size, or native
    /// pixel format.
    FrameMismatch,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the first image's header. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the next image into dst, which must be the canvas's size, in any format. Returns null once there are no more. work is unused: Netpbm needs no work memory.

pub fn decodeFrameConfig(d: *Decoder) Error!?decode.Frame

src

Reads the next image's header and returns the frame decodeFrame will decode next, without decoding it, or null once there are no more: in a raw file, only the end of the input tells.

Types

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

enum Kind

src
pub const Kind = enc.Kind

The Netpbm formats encode writes.

Fields

pbm pbm
pgm pgm
ppm ppm
pam pam
pfm pfm
plain_pbm plain_pbm
plain_pgm plain_pgm
plain_ppm plain_ppm

struct EncodeOptions

src
pub const EncodeOptions = enc.EncodeOptions

Fields

kind: ?Kind = null

The format to write; null picks PGM, PPM, or PAM from the source's channels.

maxval: u16 = 0

The maxval of PGM, PPM, and PAM, 1 to 65535; 0 picks 255 for 8-bit sources and 65535 for wider ones. PBM and PFM have none.

pfm_endian: std.builtin.Endian = .little

PFM's byte order.

module wbmp

src

WBMP, the WAP Wireless Bitmap, type 0: decode and encode.

Constants

pub const EncodeError = encoder.EncodeError

src

The errors every encoder can return. Each format's error set is these plus its own causes.

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

WBMP needs no work memory.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a WBMP file to w.

Types

module Decoder

src

A streaming WBMP decoder: reads from a std.Io.Reader, writes any PixelFormat, needs no work memory, and allocates nothing.

more

Format: the Wireless Bitmap of the WAP Wireless Application Environment specification (WAP-237, section 6 and appendix A), type 0, the only type it defines: a multi-byte integer type field (0), a fixed header octet (0: no extension headers), the width and height as multi-byte integers, then the rows, one bit per pixel, most significant bit first, each row padded to an octet. A set bit is white, a clear one black. A multi-byte integer is big-endian groups of 7 bits, each octet but the last with its top bit set. The decoder reads nothing after the last row.

Constants

pub const Error = decode.Error

src

The errors every decoder can return. Each format's error set is these plus its own specific causes.

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the header. The native format is gray8, every pixel 0 or 255. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the image into dst, which must be the image's size, in any format. Returns null once the image is decoded. work is unused: WBMP needs no work memory.

Types

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

module webp

src

WebP (RFC 9649): lossless and lossy images with alpha, and animations, decoded by Decoder; encode writes lossless and lossy.encode lossy stills.

Constants

pub const EncodeError = encoder.EncodeError

src

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs for a width by height image, or null when WebP cannot store it.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a lossless WebP file to w.

pub fn encodeAlpha(w: *Io.Writer, plane: []const u8, width: u32, height: u32, effort: u4, work: []u8) EncodeError!void

src

Writes plane, width by height alpha values, row after row, as the lossless stream an ALPH chunk with compression method 1 holds: a VP8L image stream without its header, the alpha in green (RFC 9649). The caller writes the chunk's header byte and filters the plane first, if it chooses a filter. work takes workLen(.{ .effort = effort }, width, height) bytes.

Types

module Decoder

src

A streaming WebP decoder: reads from a std.Io.Reader, writes any PixelFormat, and allocates nothing.

more

Format: RFC 9649, the WebP container and the lossless bitstream, and RFC 6386 for the lossy one. It decodes simple files and extended (VP8X) images, lossless or lossy, with a lossy image's ALPH chunk, still or animated. ICCP, EXIF, and XMP chunks before the image (or the first frame) are reported in Config.metadata, and every one goes to the blob sink as it passes; EXIF's orientation is read.

As libwebp reads them: a still image's bitstream must match the VP8X canvas, chunks before the image may come in any order (only the image chunk ends them), and chunks after it are skipped, but the RIFF payload must be all there, so a still image's decodeFrame reads to its end. An animation's chunks follow libwebp's demuxer, and its frames are composited as libwebp's animation decoder composites them, given a caller that disposes of each frame's region to transparent black.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// A chunk's size runs past the RIFF payload, a VP8X chunk is not 10
    /// bytes, or the first chunk is not VP8, VP8L, or VP8X.
    BadChunk,
    /// A prefix code in a lossless bitstream is empty, incomplete, or
    /// oversubscribed, or reads past its alphabet.
    BadPrefixCode,
    /// A lossless bitstream breaks the specification otherwise: a
    /// transform used twice, a color cache size outside 1 to 11 bits, or a
    /// backward reference before the first pixel or past the last.
    BadLossless,
    /// A lossy bitstream is not a shown key frame, its start code or size
    /// is wrong, or its first partition is larger than its chunk.
    BadVp8,
    /// An ALPH chunk's header is malformed, or its raw plane is too short.
    BadAlpha,
    /// An animation frame's ALPH chunk is decoded at the size of the VP8
    /// frame after it, which is not the size its ANMF chunk gives, and
    /// `Options.seeker` is null, so the decoder cannot go back to it.
    AlphaBehind,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame, and stops at the end of the RIFF payload.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the chunks before the image and the bitstream's header, or a lossy image's ALPH chunk header, which comes first; of an animation, the chunks through ANIM. The native format of a lossless image is bgra8, the order its pixels are decoded in; of a lossy one, rgb8, or rgba8 with an ALPH chunk; of an animation, rgba8, whose frame count is not known until the end. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the next frame into its region of dst, which must be the canvas's size, in any format, using work[0..work_len]. A still image is one frame, after which the rest of the RIFF payload is read. An animation's first frame clears the canvas outside its region to transparent black, and a frame that blends (Frame.blend is src_over) is composited over what dst holds: the caller applies each frame's disposal before the next call. Returns null after the last frame.

pub fn applyTrailer(d: *const Decoder, config: *decode.Config) void

src

Sets in config the metadata the chunks after the image or the frames held (late): image.Decoder.finalConfig calls this once decodeFrame has returned null.

pub fn decodeFrameConfig(d: *Decoder) Error!?decode.Frame

src

The frame the next decodeFrame call returns, read up to its pixels, or null where that call returns null. A still image's one frame is the canvas; an animation's is read through its ANMF fields and its image chunk's header.

Types

struct Options

src

Fields

limits: decode.Limits = .{}
blob_sink: ?decode.BlobSink = null
seeker: ?decode.Seeker = null

Lets an animation frame's ALPH chunk be decoded at the size of the VP8 frame after it when that differs from the size its ANMF chunk gives, as libwebp decodes it (AlphaBehind); see image.Seeker.

max_prefix_groups: u32 = 0

The most prefix code groups a lossless image may use, which sets how much work memory it needs (about 10 KiB a group); 0 is 2600, the most libwebp's encoder writes. An image that uses more is Unsupported.

module lossy

src

The lossy WebP encoder: one VP8 key frame (RFC 6386) in a RIFF container (RFC 9649), and an ALPH chunk when the source has alpha that is not everywhere opaque. Written from the specifications. src/encode.zig has the contract: nothing is allocated, and workLen states the work memory up front.

more
  • The source is converted with image.convert to RGB8 (RGBA8 with alpha), then to BT.601 limited-range YUV 4:2:0, a macroblock row at a time: each chroma sample from the average of its 2x2 pixels.
  • EncodeOptions.quality picks the quantizer. With segments (every effort but fast), macroblocks are clustered by their luma activity into four segments, each with its own quantizer and loop filter level: busier ones, where artifacts hide, quantize more coarsely.
  • Each macroblock's luma is predicted as one 16x16 block or as sixteen 4x4 blocks, and its chroma as two 8x8 blocks, choosing the modes that cost least in squared error plus lambda times the bits, the bits estimated from the token probabilities. Above fast, trellis quantization (vp8_encode_trellis.zig) chooses the levels the same way.
  • Coefficients are kept compactly in work memory as they are chosen, with the counts of every token. After the last macroblock the token probabilities are chosen from the counts, the token partition is coded into the spare room of the coefficients' memory (or sized, when it does not fit), the first is sized by a pass of the boolean coder that writes nothing, and the file is written in one pass.
  • Alpha goes in ALPH, compressed by the lossless encoder (src/webp/encode.zig) when that is smaller than raw.

Constants

pub const EncodeError = …

src
value
shared.Error || error{
    /// VP8 cannot store an image without rows or columns.
    EmptyImage,
}

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs for a width by height image, or null when VP8 cannot store it: with alpha_compression, the lossless encoder's for the alpha too, since the source's format is not known.

pub fn quantizerIndex(quality: u8) u7

src

The base quantizer index (0 to 127, section 9.6) for a quality: what cwebp chooses at the same quality without segments, measured at the points below and interpolated between them, so a quality means about the same in both encoders.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a lossy WebP file to w.

Types

enum Effort

src

How hard the encoder works to make the file small for its quality.

Fields

fast fast

No segments. Each block's mode is the one whose prediction is closest (4x4 blocks try only DC, TM, VE, and HE); rate and distortion choose only between 16x16 and 4x4 luma.

default default

Segments. The 16x16 and chroma modes are chosen by rate and distortion, and each 4x4 block's by rate and distortion among the three closest predictions; the chosen modes' levels are chosen again by trellis quantization.

best best

As default with every 4x4 mode tried, trellis quantization in every choice, and every macroblock tried as 4x4, after a first pass at default's search whose token statistics refine the rate estimates.

struct EncodeOptions

src

Fields

quality: u8 = 75

0 (smallest) to 100 (best); values past 100 are 100.

effort: Effort = .default
icc: ?[]const u8 = null

An ICC profile for an ICCP chunk.

exif: ?[]const u8 = null

An EXIF profile, starting with its TIFF header, for an EXIF chunk.

xmp: ?[]const u8 = null

XMP for an XMP chunk.

alpha_compression: bool = true

Whether alpha is compressed with the lossless encoder (ALPH compression 1), kept only when that is smaller than storing it raw, as libwebp does. While it is on, workLen includes the lossless encoder's work memory whatever the source, about 29 to 38 bytes per pixel at a megapixel; a caller whose images are opaque turns it off to ask for about 3.2. False stores alpha raw.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

effort: u4 = 5

How hard the encoder works to make the file small, from 0 (fastest) to 9 (smallest), as cwebp's -z levels; values above 9 act as 9.

icc: ?[]const u8 = null

An ICC profile, written as an ICCP chunk.

exif: ?[]const u8 = null

EXIF metadata, starting with its TIFF header, as an EXIF chunk.

xmp: ?[]const u8 = null

XMP metadata, as an XMP chunk.

module tiff

src

TIFF and BigTIFF: decode every page, with strips or tiles, uncompressed or compressed with PackBits, LZW, Deflate, or CCITT Group 3 or 4. Data stored behind the reader, which most writers produce, needs an image.Seeker.

Constants

pub const EncodeError = encoder.EncodeError

src

Functions

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs for a width by height image, and encodePages for pages no wider and no taller; null when it does not fit in usize.

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes src as a one-page TIFF file.

pub fn encodePages(w: *Io.Writer, pages: []const PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

Writes pages as one TIFF file, a page each, in order. work holds at least workLen for the widest and the tallest page. A compressed page is compressed once when w's free buffer holds it, and twice, the first time only to count its bytes, when it does not.

Types

module Decoder

src

A streaming TIFF decoder: reads from a std.Io.Reader, writes any PixelFormat, and allocates nothing.

more

Format: TIFF 6.0 with BigTIFF. Classic and BigTIFF files in either byte order; strips and tiles; uncompressed, PackBits, LZW, Deflate, CCITT modified Huffman, Group 3, and Group 4, and JPEG data (through image.jpeg, TIFF Technical Note 2); predictors 2 and 3; 1 to 32-bit integer and 16, 24, 32, and 64-bit float samples, chunky or planar; gray, palette, RGB, CMYK (as cmyk8 or cmyk16), and YCbCr with subsampling. Every IFD in the main chain is a page and a frame. samples.zig says how samples become the native format.

The input is read forward, as every decoder here reads it. TIFF's offsets point anywhere, and the usual writer puts the IFD after the pixels, so data behind the reader needs Options.seeker (error.DataBehind without one). With a seeker, decodeConfig walks the whole IFD chain to report the page count, a canvas as large as the largest page, the work memory the largest page needs, and a native format that holds every page; a chain that loops ends where it repeats, as in libtiff. Without one, the config is the first page's, frame_count is null when there is a second page, and a later page that does not fit it is error.PageMismatch.

Each frame is a page, written to the top-left corner of the canvas; the rest of the canvas becomes black, transparent if the native format has alpha. Work memory is the page's strip or tile offsets and byte counts, the decompressor's state, and one row of the strip or tile (one strip or tile of every plane for planar data, which interleaves them), so for chunky data it does not grow with the image's height. JPEG gray, RGB, and YCbCr decode straight to the caller's rows; other JPEG pages take a strip or tile of samples. A JPEG stream that is progressive or not interleaved, which keeps every coefficient, is error.Unsupported.

Constants

pub const Error = …

src
value
decode.Error || error{
    /// An IFD, a value, or a strip or tile lies before the reader's
    /// position, and `Options.seeker` is null.
    DataBehind,
    /// Without a seeker, a page after the first does not fit the config
    /// the first page gave: it is larger than the canvas, needs more work
    /// memory than `Config.work_len`, or has pixels `Config.native` cannot
    /// hold.
    PageMismatch,
    /// A strip or tile's data ends before its rows do.
    NotEnoughData,
    /// LZW data does not start with Clear, or has a code past the table.
    BadLzw,
    /// Deflate data is not a valid zlib stream.
    BadZlib,
    /// CCITT data has an invalid code, or runs past a row.
    BadFax,
    /// A JPEG strip or tile is not a JPEG stream `image.jpeg` reads, or
    /// its size or component count is not the strip's or tile's.
    BadJpeg,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

Starts a decoder on reader, whose buffer must hold at least image.min_buffer_len bytes. The decoder reads nothing until decodeConfig or decodeFrame.

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the header and the first page's IFD and, with a seeker, every other page's. Calling it again returns the same config.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the next page into the top-left corner of dst, which must be the canvas's size, in any format. Returns null after the last page.

pub fn decodeFrameConfig(d: *Decoder) Error!?decode.Frame

src

Reads the next page's IFD and returns the frame the next decodeFrame returns, without decoding it, or null after the last page. Calling it again returns the same frame.

Types

struct Options

src

Fields

limits: decode.Limits = .{}
blob_sink: ?decode.BlobSink = null
seeker: ?decode.Seeker = null

Moves back to data behind the reader (image.Seeker). Without it, such data is error.DataBehind.

struct EncodeOptions

src
pub const EncodeOptions = encoder.EncodeOptions

Fields

compression: Compression = .lzw
predictor: bool = true

Horizontal differencing (Predictor 2) before LZW or Deflate, for every image but a palette.

effort: Effort = .default

Deflate's effort.

palette: bool = true

Store an 8-bit RGB image of at most 256 colors as a palette when that is smaller.

density: ?decode.Density = null

XResolution, YResolution, and ResolutionUnit: per inch, per centimeter (a per-meter density over 100), or none.

rows_per_strip: ?u32 = null

The rows in each strip; null for strips of about 8 KiB.

enum Compression

src
pub const Compression = encoder.Compression

Fields

none none
packbits packbits
lzw lzw
deflate deflate

enum Effort

src
pub const Effort = encoder.Effort

How hard Deflate works, at the PNG encoder's levels.

Fields

fast fast

Greedy deflate (zlib level 6).

default default

Lazy deflate with a short search.

best best

Lazy deflate with a long search: the smallest file, the slowest.

module jxl

src

JPEG XL (ISO/IEC 18181-1 and -2): decode, and lossless encode.

Constants

pub const EncodeError = @import("encode.zig").EncodeError

src

Functions

pub fn encode(w: *Io.Writer, src: PixelBuffer, options: EncodeOptions, work: []u8) EncodeError!void

src

pub fn workLen(options: EncodeOptions, width: u32, height: u32) ?usize

src

The work memory encode needs for a width by height image, or null when JPEG XL (or this encoder) cannot store it.

Types

module Decoder

src

A streaming JPEG XL decoder: reads a bare codestream or a container from a std.Io.Reader, writes any PixelFormat, and allocates nothing.

Format: ISO/IEC 18181-1 (the codestream) and 18181-2 (the container).

Frames are coalesced as the reference decoder does: decodeFrame returns each displayed frame (the last, and every one with a duration) composited onto the canvas, after the zero-duration frames before it.

Constants

pub const float_direct = true

src

A float destination is written from the decoder's floats, not converted from the native format (plan.md decision 24); the fuzz harness checks it against the native format with a tolerance instead of exactly.

pub const Error = …

src
value
decode.Error || error{
    /// A container box breaks ISO/IEC 18181-2.
    BadBox,
    /// An entropy-coded stream is malformed.
    BadEntropy,
    /// The image data breaks the specification: an invalid tree,
    /// transform, channel layout, or blend.
    BadImage,
    /// The embedded ICC profile's encoding is malformed.
    BadIcc,
    /// The file needs more work memory than `Config.work_len` reserves:
    /// entropy codes or trees past their fixed budget,
    /// or a frame of more than twice the canvas's pixels.
    TooComplex,
    /// `decodeJpeg`: the codestream cannot hold a recompressed JPEG.
    NotJpeg,
}

Functions

pub fn init(reader: *Io.Reader, options: Options) Decoder

src

pub fn decodeConfig(d: *Decoder) Error!decode.Config

src

Reads the headers: the signature, size, and image metadata.

pub fn decodeFrame(d: *Decoder, dst: PixelBuffer, work: []u8) Error!?decode.Frame

src

Decodes the next displayed frame into dst.

pub fn skim(d: *Decoder, work: []u8, s: *Skim) Error!void

src

Reads every frame's header and table of contents and skips its sections, to say in s how the frames are drawn without drawing them: for this package's oracle, which picks its comparison before it decodes, not for callers. s keeps what the frames before an error said. Uses work[0..decodeConfig().work_len] and leaves nothing more to decode.

pub fn jpegWorkLen(d: *Decoder) Error!usize

src

The work memory decodeJpeg needs, from the headers.

pub fn decodeJpeg(d: *Decoder, coefs: []i16, work: []u8) Error!Jpeg

src

For rebuilding a JPEG from its jbrd box: reads the codestream's one frame as a recompressed JPEG's coefficients into coefs, which holds at least Jpeg.maxCoefs(width, height), using work[0..jpegWorkLen()] and making no pixels. Call it instead of decodeFrame, after decodeConfig. The ICC profile goes to Options.blob_sink as usual. Fails with NotJpeg when the frame cannot be a JPEG's: VarDCT YCbCr with DCT8 blocks only, raw quantization tables, the image's size, and no extra channels, animation, upsampling, patches, splines, noise, or LF frame.

Types

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

struct Jpeg

src
pub const Jpeg = vardct.Jpeg

A recompressed JPEG's coefficients, from decodeJpeg.

Fields

h: [3]u4

JPEG sampling factors, 1 or 2.

v: [3]u4
blocks_x: [3]u32

Each component's blocks across and down: whole MCUs.

blocks_y: [3]u32
quant: [3][64]u16

Each component's quantization table, in natural order.

coefs: [3][]i16

Each component's quantized coefficients, 64 a block in zigzag order (the order a JPEG's scans code them, so the writer reorders nothing), rows of blocks_x blocks.

got_quant: bool = false
ratio: [3][64]i32 = undefined

Per component and coefficient in zigzag order, the ratio of the luma and the component's quantization steps in cfl_bits fixed point, which chroma from luma scales by.

Functions

pub fn maxCoefs(width: u32, height: u32) usize

src

The most coefficients any sampling of a width by height image takes: 12 blocks a 16-pixel square (three components unsubsampled).

pub fn init(fh: *const headers.FrameHeader, d: *const headers.Dims, mem: []i16) Error!Jpeg

src

Lays out the coefficients of frame fh in mem.

pub fn sink(j: *Jpeg) CoeffSink

src

struct Skim

src

How skim finds a codestream's frames drawn.

Fields

float: bool = false

A frame is drawn in floats (float_frames): its samples are the specification's within the conformance bounds, not exact.

splines: bool = false

A frame draws splines, which the conformance bounds give more room.

module JpegReconstructor

src

Rebuilds the JPEG a JPEG XL file was transcoded from (cjxl --lossless_jpeg=1), byte for byte: the markers, tables, metadata, and entropy-coded scans from the jbrd box (jbrd.zig), and the quantized coefficients and quantization tables from the codestream, with no pixels. Allocates nothing: workLen states the work memory run needs.

more

The box is read twice, once to size the work memory and once into it, and the Exif, xml , and codestream boxes may come before or after it, so the reader must be able to move back: Options.seeker is required (error.NeedsSeeker).

var r = JpegReconstructor.init(reader, .{ .seeker = .file(&file_reader) });
const work = try gpa.alloc(u8, try r.workLen());
try r.run(writer, work);

Constants

pub const Error = …

src
value
Decoder.Error || jbrd.Error || error{
    /// The file has no `jbrd` box: it was not transcoded from a JPEG.
    NoJbrd,
    /// `Options.seeker` is null.
    NeedsSeeker,
    /// The writer failed.
    WriteFailed,
}

The codestream decoder's errors, the box's, and these.

Functions

pub fn init(reader: *Io.Reader, options: Options) JpegReconstructor

src

pub fn workLen(r: *JpegReconstructor) Error!usize

src

The work memory run needs. Reads the container's box headers, the jbrd box, and the codestream's headers.

pub fn run(r: *JpegReconstructor, writer: *Io.Writer, work: []u8) Error!void

src

Writes the original JPEG to writer, using work[0..workLen()].

Types

module jbrd

src

The box and the JPEG writer, for the fuzz target.

Constants

pub const BrotliBuffer = brotli.decode.Buffer

src

The Brotli one-shot decoder's state, 2.7 MB, in the caller's memory.

pub const Error = …

src
value
error{
    ReadFailed,
    /// The box ends inside the bundle.
    Truncated,
    /// The box breaks the bundle's constraints: a marker list without EOI
    /// or scans, an APP or COM marker shorter than its length field, a
    /// component or table index out of range, a Huffman code without its
    /// terminal symbol or with a symbol twice, a table used before a DHT
    /// defines it, nonzero padding before the Brotli stream, or a Brotli
    /// stream that is malformed or does not hold exactly the declared bytes.
    BadJbrd,
    /// More APP markers holding EXIF or XMP than one each, as libjxl.
    Unsupported,
}

pub const max_markers = 16384

src

pub const max_block = 3 << 26

src

pub const max_huffman = 26 + 63

src

pub const icc_tag = "ICC_PROFILE\x00"

src

pub const exif_tag = "Exif\x00\x00"

src

pub const xmp_tag = "http://ns.adobe.com/xap/1.0/\x00"

src

pub const icc_head = 3 + icc_tag.len + 2

src

Bytes before an ICC marker's share of the profile: type, length, tag, sequence number, and count.

pub const zigzag = …

src
value
[64]u8{
    0,  1,  8,  16, 9,  2,  3,  10, 17, 24, 32, 25, 18, 11, 4,  5,
    12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6,  7,  14, 21, 28,
    35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
    58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
}

The zigzag sequence's positions in natural order.

pub const max_correction_bytes = (0x7fff * 63 + 7) / 8 + 8

src

The bytes an AC refinement scan's held correction bits take: 0x7FFF blocks of up to 63, packed.

pub const WriteError = Error || Io.Writer.Error

src

Functions

pub fn read(b: *Bits, mem: *Mem) Error!Jbrd

src

Reads the bundle and the Brotli stream's length from b, positioned at the box's first byte. With a counting mem, nothing is stored and the slices are empty; mem.used is then what a real parse needs, beside payload_len bytes for the Brotli stream's contents.

pub fn split(j: *Jbrd, compressed: []const u8, out: []u8, buffer: *BrotliBuffer) Error!void

src

Decompresses the Brotli stream compressed (the box's bytes after the bundle) into out, exactly j.payload_len bytes, and points the APP markers of no known type, the COM markers, the inter-marker data, and the tail at their bytes. The stream must end at the box's last byte.

pub fn decompressExact(compressed: []const u8, out: []u8, buffer: *BrotliBuffer) Error!void

src

Decompresses the Brotli stream compressed into exactly out.len bytes. The stream must end at its last byte: libjxl rejects bytes after it.

pub fn zigzagged(blk: @Vector(64, i16)) @Vector(64, i16)

src

A block's coefficients in zigzag order, in one shuffle.

pub fn write(w: *Io.Writer, j: *Jbrd, img: *const Image, scratch: []u8) WriteError!void

src

Writes the JPEG: SOI, then each marker the box lists, with the scans' entropy-coded data from img. scratch holds at least max_correction_bytes when a scan refines AC coefficients.

Types

enum AppType

src
pub const AppType = enum(u2)

Where an APP marker's bytes come from: the Brotli stream, or the codestream's ICC profile, the Exif box, or the xml box.

Fields

unknown unknown
icc icc
exif exif
xmp xmp

struct App

src

Fields

type: AppType
size: u32

The marker's bytes after 0xFF: its type, length, and contents.

data: []u8 = &.{}

struct Piece

src

A run of bytes from the Brotli stream: a COM marker after 0xFF, bytes between markers, or the bytes after EOI.

Fields

size: u32
data: []u8 = &.{}

struct Quant

src

Fields

precision: u1

Pq: 0 for 8-bit values, 1 for 16-bit.

index: u2

Tq, the table's slot.

is_last: bool

The last table of its DQT marker.

struct Component

src

Fields

id: u8
quant: u2

struct Huffman

src

Fields

slot: u8

Tc << 4 | Th.

is_last: bool
counts: [17]u16

Codes of each length 1 to 16, counting the terminal symbol (256) that ends values at the longest length; all zero for an empty table.

values: []const u8

The symbols in code order, without the terminal one.

struct ScanComponent

src

Fields

index: u2
dc: u2
ac: u2

struct ZeroRun

src

Fields

block: u32

The block, counted from the scan's first.

count: u8

ZRL symbols the original wrote before the block's EOB, 1 to 4.

struct Scan

src

Fields

components: [3]ScanComponent
ss: u6
se: u6
ah: u4
al: u4
reset_points: []const u32

Blocks before which the original ended an EOB run early.

zero_runs: []const ZeroRun

struct Jbrd

src

The parsed box. Slices point into work memory.

Fields

markers: []const u8

Every marker after SOI, in file order, by its second byte; 0xFF stands for bytes between markers. The last is EOI (0xD9).

apps: []App
coms: []Piece
quant: [4]Quant
num_quant: u3
components: [3]Component
huffman: []const Huffman
scans: []const Scan
inter_marker: []Piece
tail: Piece
padding: ?[]const u8

The bits that pad each entropy-coded segment to a byte, in order, packed LSB first; null when every padding bit is 1.

payload_len: u64

Bytes of the Brotli stream's contents.

refines: bool

Whether a scan refines AC coefficients, which needs max_correction_bytes of scratch to write.

icc_len: u64

The bytes ICC, EXIF, and XMP markers take from elsewhere.

exif_len: ?u32
xmp_len: ?u32

struct Mem

src

Work memory for parsing, or a count of what parsing needs when buf is empty. Each allocation counts its worst alignment, so a count holds for any base address.

Fields

buf: []u8 = &.{}
counting: bool = false
used: usize = 0

Functions

pub fn alloc(m: *Mem, comptime T: type, n: usize) Error![]T

src

struct Bits

src

LSB-first bits from at most left bytes of a reader.

Fields

r: *Io.Reader
left: u64
buf: u64 = 0
n: u7 = 0
pos: u64 = 0

Bits consumed.

Functions

pub fn init(r: *Io.Reader, len: u64) Bits

src

pub fn bits(b: *Bits, n: u6) Error!u32

src

pub fn boolean(b: *Bits) Error!bool

src

pub fn alignToByte(b: *Bits) Error!void

src

Skips to a byte boundary; the bits skipped are zero.

pub fn remaining(b: *const Bits) u64

src

Bytes of the box left after the bits read, at a byte boundary.

struct Image

src

The image data the box leaves to the codestream, per JPEG component in the box's order.

Fields

width: u32
height: u32
h: [3]u4

Sampling factors, 1 or 2.

v: [3]u4
quant: [3][64]u16

Each component's quantization table, in natural order.

coefs: [3][]const i16

Each component's quantized coefficients, 64 a block in zigzag order (zigzagged), blocks_x(c) by blocks_y(c) blocks (whole MCUs).

icc: []const u8 = &.{}

The codestream's ICC profile, the Exif box's contents (with its 4-byte TIFF header offset), and the xml box's.

exif: ?[]const u8 = null
xmp: ?[]const u8 = null

Functions

pub fn mcusX(img: *const Image, n: usize) u32

src

pub fn mcusY(img: *const Image, n: usize) u32

src

pub fn blocksX(img: *const Image, n: usize, c: usize) u32

src

pub fn blocksY(img: *const Image, n: usize, c: usize) u32

src

struct Options

src
pub const Options = decode.Options

Options every decoder takes. A format with more options has its own Options with limits and blob_sink, seeker if it can move back, and its own after them; image.Decoder passes on the fields it has.

Fields

limits: Limits = .{}
blob_sink: ?BlobSink = null

Receives the bytes of each metadata blob (ICC profile, EXIF, XMP) as the decoder reads past it; see BlobSink.

seeker: ?Seeker = null

Lets a format whose offsets can point behind the reader (ICO's directory, TIFF's IFDs) move back; see Seeker. Formats read forward without one, and those that never move back ignore it or lack the field.

struct EncodeOptions

src
pub const EncodeOptions = @import("encode.zig").EncodeOptions

Fields

effort: Effort = .default

enum Effort

src
pub const Effort = @import("encode.zig").Effort

How hard the encoder works to make the file small.

Fields

fast fast

The gradient predictor, a small tree, few samples.

default default

A choice of four predictors with the weighted predictor and its property.

best best

Every predictor, more samples and thresholds, a larger tree.