heic

Pure Rust HEIC/HEIF image decoder. No C/C++ dependencies, no unsafe code, 4 runtime crates.
#![forbid(unsafe_code)]— zero unsafe blocks in the entire codebaseno_std + alloccompatible (compiles for wasm32-unknown-unknown)- AVX2/SSE4.1 SIMD acceleration with automatic scalar fallback
- Optional tile-parallel decoding via rayon
Status
Decodes most HEIC files from iPhones and cameras. 103/162 test files decode successfully. Best quality: 77.3 dB PSNR (BT.709), 73% pixel-exact on example.heic.
What works
- HEIF container parsing (ISOBMFF boxes, grid images, overlays, identity-derived items)
- Full HEVC I-frame decoding (VPS/SPS/PPS, CABAC, intra prediction, transforms)
- Deblocking filter and SAO (Sample Adaptive Offset)
- YCbCr→RGB with BT.601/BT.709/BT.2020 matrices (full + limited range)
- CICP color info from HEVC VUI and HEIF colr nclx (container overrides codec)
- 10-bit HEVC with transparent 8-bit downconvert or 16-bit output preservation
- Alpha plane decoding from auxiliary images
- HDR gain map extraction (Apple
urn:com:apple:photo:2020:aux:hdrgainmap) - EXIF, XMP, and ICC profile extraction (zero-copy where possible)
- Thumbnail decode, image rotation/mirror transforms (ipma ordering)
- HEVC scaling lists (custom dequantization matrices)
- AVX2 SIMD: color conversion, IDCT 8/16/32, residual add, dequantize
- SSE4.1 SIMD: IDST 4x4
- Tile-parallel grid decoding via rayon (
parallelfeature)
Known limitations
- I-slices only (sufficient for HEIC still images; no inter prediction for video)
- PQ/HLG transfer functions: parsed and exposed via
ImageInfo, but no EOTF applied — callers handle tone-mapping
Features
| Feature | Default | Description |
|---|---|---|
std |
yes | Standard library support. Disable for no_std + alloc. |
parallel |
no | Parallel tile decoding via rayon. Implies std. |
Usage
use ;
let data = read?;
let output = new.decode?;
println!;
Limits and cancellation
use ;
let mut limits = default;
limits.max_width = Some;
limits.max_height = Some;
limits.max_pixels = Some;
limits.max_memory_bytes = Some;
let output = new
.decode_request
.with_output_layout
.with_limits
.decode?;
Probe without decoding
use ImageInfo;
let info = from_bytes?;
println!;
// CICP color info also available:
// info.color_primaries, info.transfer_characteristics, info.matrix_coefficients, info.video_full_range
Zero-copy into pre-allocated buffer
let info = from_bytes?;
let mut buf = vec!;
let = new
.decode_request
.with_output_layout
.decode_into?;
For grid images (most iPhone photos), decode_into streams tile color conversion directly into the output buffer, avoiding the intermediate full-frame YCbCr allocation.
Metadata extraction
use Cow;
let decoder = new;
// Zero-copy for single-extent items, owned for multi-extent
let exif: = decoder.extract_exif?; // raw TIFF bytes
let xmp: = decoder.extract_xmp?; // raw XML bytes
let icc: = decoder.extract_icc?; // ICC profile bytes
let thumb = decoder.decode_thumbnail?; // smaller preview
HDR gain map
let gainmap = new.decode_gain_map?;
// gainmap.data: Vec<f32> (normalized 0.0–1.0), gainmap.width, gainmap.height
// Apply Apple HDR reconstruction:
// sdr_linear = sRGB_EOTF(sdr_pixel)
// gain_linear = sRGB_EOTF(gainmap_pixel)
// scale = 1.0 + (headroom - 1.0) * gain_linear
// hdr_linear = sdr_linear * scale
Performance
Benchmarked on AMD Ryzen 9 7950X, WSL2, Rust 1.93, release profile (thin LTO, codegen-units=1).
| Image | Time |
|---|---|
| 1280x854 (single tile) | 54 ms |
| 3024x4032 (48-tile, sequential) | 451 ms |
3024x4032 (48-tile, parallel) |
180 ms |
| Probe (metadata only) | 1.3 µs |
| EXIF extraction | 4.4 µs |
SIMD-accelerated on x86-64 (AVX2 for color conversion, IDCT 8/16/32, residual add, dequantize; SSE4.1 for IDST 4x4). Scalar fallback on other architectures.
Dependencies
4 runtime crates (default features), none with C/FFI:
heic
├── archmage — SIMD dispatch via CPU feature tokens
│ └── safe_unaligned_simd — safe wrappers over std::arch intrinsics
├── enough — cooperative cancellation (0 unsafe)
├── safe_unaligned_simd
└── whereat — error location tracking (deny(unsafe_code))
With parallel: adds rayon + crossbeam (6 more crates, all pure Rust).
Memory
Use DecoderConfig::estimate_memory() to check memory requirements before decoding. decode_into() uses a streaming path for grid images that reduces peak memory by ~60% compared to decode().
Image tech I maintain
| State of the art codecs* | zenjpeg · zenpng · zenwebp · zengif · zenavif (rav1d-safe · zenrav1e · zenavif-parse · zenavif-serialize) · zenjxl (jxl-encoder · zenjxl-decoder) · zentiff · zenbitmaps · heic · zenraw · zenpdf · ultrahdr · mozjpeg-rs · webpx |
| Compression | zenflate · zenzop |
| Processing | zenresize · zenfilters · zenquant · zenblend |
| Metrics | zensim · fast-ssim2 · butteraugli · resamplescope-rs · codec-eval · codec-corpus |
| Pixel types & color | zenpixels · zenpixels-convert · linear-srgb · garb |
| Pipeline | zenpipe · zencodec · zencodecs · zenlayout · zennode |
| ImageResizer | ImageResizer (C#) — 24M+ NuGet downloads across all packages |
| Imageflow | Image optimization engine (Rust) — .NET · node · go — 9M+ NuGet downloads across all packages |
| Imageflow Server | The fast, safe image server (Rust+C#) — 552K+ NuGet downloads, deployed by Fortune 500s and major brands |
* as of 2026
General Rust awesomeness
archmage · magetypes · enough · whereat · zenbench · cargo-copter
And other projects · GitHub @imazen · GitHub @lilith · lib.rs/~lilith · NuGet (over 30 million downloads / 87 packages)
License
Dual-licensed: AGPL-3.0 or commercial.
I've maintained and developed open-source image server software — and the 40+ library ecosystem it depends on — full-time since 2011. Fifteen years of continual maintenance, backwards compatibility, support, and the (very rare) security patch. That kind of stability requires sustainable funding, and dual-licensing is how we make it work without venture capital or rug-pulls. Support sustainable and secure software; swap patch tuesday for patch leap-year.
Your options:
- Startup license — $1 if your company has under $1M revenue and fewer than 5 employees. Get a key →
- Commercial subscription — Governed by the Imazen Site-wide Subscription License v1.1 or later. Apache 2.0-like terms, no source-sharing requirement. Sliding scale by company size. Pricing & 60-day free trial →
- AGPL v3 — Free and open. Share your source if you distribute.
See LICENSE-COMMERCIAL for details.
AI-Generated Code Notice
Developed with Claude (Anthropic). Not all code manually reviewed. Review critical paths before production use.