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 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 isPremultiplied(f: PixelFormat) bool
src
The bytes width pixels take, or null if that overflows usize.
Types
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
value
error{
/// The buffer is smaller than its dimensions and stride need, or
/// the stride is narrower than a row.
BufferTooSmall,
}Functions
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.
The number of bytes a tightly packed buffer of these dimensions
takes, or null if it overflows usize.
Checks that every row fits in pixels. Decoders call this before
writing, since the fields are public.
Row y, exactly width pixels long. Asserts y < height and a
buffer that passed check.
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 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 isPremultiplied(f: PixelFormat) bool
src
The bytes width pixels take, or null if that overflows usize.
Types
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
value
error{
/// The buffer is smaller than its dimensions and stride need, or
/// the stride is narrower than a row.
BufferTooSmall,
}Functions
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.
The number of bytes a tightly packed buffer of these dimensions
takes, or null if it overflows usize.
Checks that every row fits in pixels. Decoders call this before
writing, since the fields are public.
Row y, exactly width pixels long. Asserts y < height and a
buffer that passed check.
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 / maxone way andc * maxrounded to nearest, clamped to 0..max, the other; NaN is 0. - Premultiplying is
c * a / 65535and unpremultiplyingc * 65535 / aon 16-bit samples, both truncated; unpremultiplying clamps to 65535 and gives 0 whereais 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 isc * a * 257 / 65280truncated and unpremultiplyingc * 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) >> 16on 16-bit samples (Rec. 601 luma), and0.299 R + 0.587 G + 0.114 Bwith 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, withmax255 or 65535 (ink * blackin float). CMYK from color is its naive inverse on 16-bit samples: black ism, the largest of R, G, and B, and each inkc * 65535 / m, rounded (c / min float), 0 wheremis 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
Functions
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.
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.
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
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
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.
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²).
max_luminance: f32
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
From an EXIF or TIFF orientation value, 1 to 8.
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
Whether a piece of n bytes at at, passed with this blob, is the
blob's last.
Types
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
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
Functions
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.
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
The package namespace that decodes this format: cur is ico's.
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
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
Whether this build decodes format.
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 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
Writes src as a BMP file.
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
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
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 max_entries = decoder.max_entries
src
The most entries a file may have.
pub const EncodeError = encoder.Error
src
Functions
Writes src as a one-entry ICO or CUR file.
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.
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
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
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
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
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
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.
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
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
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.
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
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
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
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.
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.
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
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.
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
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
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
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
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
value
decode.Error || error{
/// A run-length packet goes past the last pixel.
RunPastEnd,
}Functions
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.
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
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
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, so255#c\nends 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 isBadHeader; a width or height over 2^32 - 1 isImageTooLarge. - PAM:
P7and 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 isBadHeader. The tuple types BLACKANDWHITE and GRAYSCALE (read the same way, as gray scaled by maxval), RGB, and their_ALPHAforms 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 isBadHeader. 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, isUnsupported. - PFM:
PF(color) orPf(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
(
FrameMismatchotherwise).Config.frame_countis 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
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
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.
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
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
The errors every decoder can return. Each format's error set is these plus its own specific causes.
Functions
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
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
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
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.convertto 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.qualitypicks the quantizer. With segments (every effort butfast), 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
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
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
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
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
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.
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
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.
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 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.
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
The most coefficients any sampling of a width by height image
takes: 12 blocks a 16-pixel square (three components unsubsampled).
Lays out the coefficients of frame fh in mem.
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
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
The work memory run needs. Reads the container's box headers, the
jbrd box, and the codestream's headers.
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.
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_huffman = 26 + 63
src
Bytes before an ICC marker's share of the profile: type, length, tag, sequence number, and count.
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
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.
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.
A block's coefficients in zigzag order, in one shuffle.
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
struct
Scan
src
Fields
components: [3]ScanComponent
num_components: u2
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
num_components: u2
huffman: []const Huffman
scans: []const Scan
restart_interval: u16
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.
padding_bits: u32
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
Bits
src
LSB-first bits from at most left bytes of a reader.
Fields
Functions
pub fn alignToByte(b: *Bits) Error!void
src
Skips to a byte boundary; the bits skipped are zero.
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
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