zenavif-serialize 0.1.0

AVIF container serializer (MPEG/HEIF/MIAF/ISO-BMFF) with animation and grid support
Documentation

zenavif-serialize

crates.io docs.rs license

AVIF container serializer (muxer) in pure Rust. Creates MPEG/HEIF/MIAF/ISO-BMFF boxes for still images, animations, and grid layouts. Only dependency is arrayvec.

Together with zenrav1e, it enables pure-Rust AVIF encoding.

Fork of avif-serialize

Forked from avif-serialize v0.8.8 by Kornel Lesinski. Rebased on upstream as of 2026-02-14.

Changes from upstream (+2,188 lines, -55 lines):

  • AnimationAnimatedImage builder with per-frame durations, keyframe control, alpha track (animated.rs, 795 lines)
  • Grid/tiled imagesGridImage builder for tile-based encoding up to 256x256 (grid.rs, 695 lines)
  • Transforms — rotation (irot), mirror (imir), clean aperture crop (clap), pixel aspect ratio (pasp)
  • Metadata — ICC profile, EXIF, and XMP embedding as separate items with item references
  • Builder APIAviffy builder with #[non_exhaustive] types for forward compatibility

Original still-image serialization code is largely unchanged.

Features

  • Still images with optional alpha channel (separate monochrome AV1 plane)
  • Animated AVIF with per-frame durations and keyframe control
  • Grid/tiled images (up to 256x256 tiles) for large images
  • HDR metadata — content light level (clli) and mastering display color volume (mdcv)
  • Transforms — rotation, mirror, clean aperture crop, pixel aspect ratio
  • Color spaces — full CICP support (BT.709, BT.2020, Display P3, PQ, HLG, etc.)
  • ICC profiles, EXIF, and XMP metadata embedding
  • 8/10/12-bit depth
  • no_std compatible (with alloc)

Usage

Add to Cargo.toml:

[dependencies]
zenavif-serialize = "0.1"

Still image (minimal)

Compress your pixels with an AV1 encoder first, then wrap the bitstream:

let avif_bytes = zenavif_serialize::serialize_to_vec(
    &color_av1_data,  // AV1 bitstream
    None,             // alpha (optional)
    width, height, 8, // dimensions and bit depth
);

Still image (configured)

use zenavif_serialize::{Aviffy, ColorPrimaries, TransferCharacteristics};

let avif_bytes = Aviffy::new()
    .set_color_primaries(ColorPrimaries::Bt2020)
    .set_transfer_characteristics(TransferCharacteristics::Smpte2084)
    .set_content_light_level(1000, 400)
    .set_rotation(1) // 90 degrees CCW
    .to_vec(&color_av1, alpha_av1.as_deref(), width, height, 10);

Animation

use zenavif_serialize::{AnimatedImage, AnimFrame};

let mut anim = AnimatedImage::new();
anim.set_timescale(1000); // milliseconds
anim.set_color_config(av1c);

let frames = vec![
    AnimFrame::new(&frame0_av1, 33).with_sync(true),
    AnimFrame::new(&frame1_av1, 33),
    AnimFrame::new(&frame2_av1, 33),
];

let avif_bytes = anim.serialize(width, height, &frames, &seq_header, None);

Grid (tiled)

use zenavif_serialize::GridImage;

let mut grid = GridImage::new();
grid.set_color_config(av1c);

let avif_bytes = grid.serialize(
    2, 2,           // rows x columns
    2048, 2048,     // output dimensions
    1024, 1024,     // tile dimensions
    &[&tile0, &tile1, &tile2, &tile3],
    None,           // alpha tiles (optional)
)?;

Compatibility

Output is tested against three independent AVIF parsers: avif-parse, zenavif-parse, and mp4parse (Mozilla). Browser compatibility has not been independently verified.

License

BSD-3-Clause. Original code copyright Cloudflare, Inc. Fork additions copyright Imazen LLC.