A pure-Rust HEIF/HEIC image decoder.
No C dependencies · no unsafe code · runs everywhere Rust runs, including the browser.
▶ Try it in your browser — drop a .heic photo; it is decoded locally by heifer compiled to WebAssembly.
Why Heifer?
HEIC is the default photo format on iPhones and many Android phones, yet reading it from Rust has meant leaning on C and C++.
Heifer is an independent implementation of HEIF and HEVC written entirely in safe Rust, validated
against the official conformance bitstreams. Add one line to Cargo.toml and it builds anywhere Rust
builds (Linux, macOS, Windows and WebAssembly are tested in CI), with no system library to install.
Features
- Correct: identical to ffmpeg on 62/62 comparable HEVC conformance bitstreams; 41 also verified against the reference decoder's MD5 hashes.
- Real photos: iPhone (48-tile grids, rotation, spatial photos), Samsung 200 MP, Xiaomi, Sony.
- Safe:
#![forbid(unsafe_code)], size limits against malicious files, fuzzed continuously on CI. - Complete: alpha, overlays, crop/rotation/mirror, 8–12 bit, EXIF/XMP/ICC metadata.
- Portable: optional
imageintegration, and it compiles to WebAssembly (≈ 250 KB).
Quick start
[]
= "0.1"
Or try the examples on your own photos:
Decode a HEIC
let bytes = read?;
let image = decode?; // primary image, with alpha, crop/rotation/mirror applied
println!;
let rgba: = image.to_rgba8; // or to_rgb8(); image.data keeps 16-bit samples
Limit threads and image size, for example on a server that accepts uploads:
let options = Options ;
let image = decode_with_options?;
Read metadata
Read EXIF, XMP and the ICC profile without decoding pixels:
let meta = read_metadata?;
if let Some = meta.exif_fields
let icc: = meta.icc_profile; // also meta.exif (raw TIFF) and meta.xmp
image crate integration
= { = "0.1", = ["image"] }
register_image_decoder_hooks;
let img = open?; // .heic / .heif / .hif, plus content detection
HeifDecoder implements image::ImageDecoder (8- and 16-bit RGB/RGBA, EXIF/XMP/ICC). The HEIF
orientation is already applied, so it is never applied twice.
Supported formats / features
| Supported | Not yet | |
|---|---|---|
| Container | grids, overlays (iovl), alpha planes, clap/irot/imir, thumbnails, multiple images |
iloc construction method 2 |
| HEVC | Main, Main 10, Main Still Picture, intra Range Extensions: 8–12 bit, 4:0:0 / 4:2:0 / 4:2:2 / 4:4:4, tiles, WPP, PCM, scaling lists, deblocking, SAO | extended precision (16-bit), image sequences (inter prediction) |
| Colour | YCbCr → RGB, BT.601 / 709 / 2020, full and limited range (colr nclx, else HEVC VUI) |
applying ICC profiles, HDR gain maps |
| Metadata | EXIF (with a small reader for camera, date, orientation, GPS), XMP, ICC | IPTC |
| Encoding | — | planned (see roadmap) |
Conformance
The first picture of 66 official conformance bitstreams (ITU-T H.265.1) covering Main, Main 10 and the Range Extensions:
| Check | Result |
|---|---|
| Identical to ffmpeg, sample for sample | 62 / 62 comparable streams |
| Verified against the reference decoder's picture hash (MD5 / checksum SEI) | 41 streams, including 3 that ffmpeg cannot decode |
| Not supported | 1 (16-bit extended precision tools) |
Robustness
Five cargo-fuzz targets with HEIF/HEVC dictionaries run around the clock on GitHub Actions (5h15 sessions every 6 hours): full decoding, container parsing, HEVC decoding, a parallel-vs-sequential differential check and a CABAC round trip. Fuzzing already found and fixed a memory exhaustion bug.
Real-world compatibility
| Photo | Content | Result |
|---|---|---|
| iPhone 13 Pro | 4032×3024, 48-tile grid, HDR gain map, depth map | ≈ 61 dB vs ffmpeg |
| iPhone 8 Plus | rotated 270° | correct orientation |
| iPhone 15 Pro | spatial (stereo) photo | ≈ 62 dB |
| Samsung Galaxy S24 Ultra | 200 MP, 768 tiles | decoded (ffmpeg fails) |
| Xiaomi, Sony, others | grids, 8/10/12-bit, alpha | ✓ |
| Corrupted / truncated files | clean errors, never a panic |
The remaining differences with ffmpeg are in heifer's favour: it honours the declared image sizes and grid crops, and decodes the file's primary image rather than the largest one.
Performance
Decode time on a 10-core Apple Silicon Mac (release build, median of several runs), compared with
ffmpeg decoding the same file:
| Image | heifer | heifer, 1 thread | ffmpeg |
|---|---|---|---|
| Xiaomi, 5 MP | 33 ms | 130 ms | 57 ms |
| iPhone 13 Pro, 12 MP (48 tiles) | 42 ms | 208 ms | 96 ms |
| 8000×6000, 48 MP | 203 ms | 1.2 s | 571 ms |
| Galaxy S24 Ultra, 200 MP (768 tiles) | 0.65 s | 2.7 s | fails |
| In the browser (WebAssembly, 1 thread), 1280×854 | ~115 ms |
Grid tiles are decoded in parallel; the iPhone photo scales from 207 ms on 1 thread to 39 ms on 10:
On multi-core machines heifer decodes these photos faster than ffmpeg. Single-threaded decoding is still slower than ffmpeg; SIMD versions of the hot loops are planned.
Architecture
photo.heic ──▶ container ──▶ HEVC bitstream ──▶ HEVC decoder ──▶ assembly ──▶ RGB(A)
(heifer-isobmff) per tile (heifer-hevc-dec) (heifer)
- Container: the ISOBMFF boxes are parsed into items and properties: grids, alpha planes, transforms, metadata.
- Bitstream: each tile's HEVC data is extracted with its parameter sets.
- Decoding: CABAC, intra prediction, inverse transforms, deblocking and SAO; grid tiles are decoded in parallel.
- Assembly: tiles are stitched, alpha attached, YCbCr converted to RGB, and crop/rotation/mirror applied.
Crates
heifer decode(), read_metadata(), image crate integration
├── heifer-isobmff HEIF container: boxes, items, properties, grids, metadata
└── heifer-hevc-dec HEVC decoder: CABAC, intra prediction, transforms, deblocking, SAO
heifer-hevc-enc HEVC encoder (work in progress: CABAC encoder)
The lower-level crates can be used directly, for example to extract an HEVC stream:
let file = parse?;
let tiles = file.referenced_items;
let hevc = file.hevc_bitstream?; // Annex B, decodable by heifer-hevc-dec or ffmpeg
Roadmap
- 0.1 — Decoder: container, HEVC, conformance, real photos, metadata,
image, WebAssembly, fuzzing - Next: HDR gain maps (Apple / ISO 21496-1), ICC colour management, SIMD for faster single-threaded decoding
- Encoder: HEIF writing, minimal HEVC intra encoder, then better compression, 10-bit and alpha
See CHANGELOG.md for details.
Development
Inspecting files
Conformance (≈ 23 MB from itu.int, not committed)
Fuzzing (nightly toolchain and cargo install cargo-fuzz)
WebAssembly demo (rustup target add wasm32-unknown-unknown, cargo install wasm-bindgen-cli --version 0.2.129)
&&
License
Licensed under either of Apache License 2.0 or MIT, at your option.
Patents. HEVC is covered by patents. Heifer is an independent implementation for research and interoperability; users are responsible for complying with applicable patent licensing in their jurisdiction.
Acknowledgements. Validation relies on the ITU-T HEVC conformance bitstreams, the test files of pillow-heif and Nokia's HEIF samples, the fuzzing corpus of libheif, and ffmpeg as a reference decoder.