Files
lightcraft/crates/heif/README.md
Exalted5373andClaude Opus 5.5 90361935ba LR-IMP-FORMATS: HEIC decodes like libheif; release builds include it
heic-rs reconstructs iPhone HEVC tiles bit-exactly (checked against libde265), but
its colour stage was 2-27 code values off libheif on every iPhone photo: it ignores
the HEVC VUI and assumes BT.709 limited range. lightcraft-heif now converts YCbCr
itself (nclx, else VUI, else H.265 defaults; nearest chroma, bilinear for odd clap
offsets, as libheif), inherits tile ICC/nclx on grids, follows libheif's imir axis
and clap rounding, and outputs 16-bit RGB. Measured on 30 real and synthetic
files: within 1 code value of libheif (pillow-heif 1.8 / libheif 1.23).

Also: HEIF header reader for import (no pixel decode), embedded thumbnail for small
decodes, nclx/VUI colour hint (shared CICP mapping with PNG), clear 4:2:2/4:4:4
Unsupported error, Format::not_decodable as the one source of "why not" (import
reports "HEIC/HEIF support isn't included in this build"), `.heif` imports.
Release packaging and Nix build with the heif feature, as whats-new promised.
lightcraft_heif::testdata writes lossless (PCM) synthetic HEICs for the tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:38:00 -07:00

48 lines
3.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# lightcraft-heif
The optional HEIF / HEIC decoder of LightCraft: iPhone and Mac photos. [`heic-rs`](https://github.com/tbraun96/heic-rs)
(pure Rust, no `unsafe`, MIT OR Apache-2.0, written from the H.265 / HEIF specifications) reads the
container and reconstructs the HEVC pictures; this crate turns them into 16-bit RGB itself so the
result matches libheif to within one code value:
- the colour description is the item's `colr nclx` (or its first tile's), else the HEVC VUI
(iPhones: full range), else the H.265 defaults; an unspecified matrix is BT.601. heic-rs alone
assumes BT.709 limited range, about 8 code values off on every iPhone photo;
- chroma is upsampled by nearest neighbour, or centred bilinear when a `clap` starts on an odd
pixel, as libheif does;
- `imir` axis 0 flips top and bottom, as libheif writes and reads it (heic-rs names it the other way);
- a grid's ICC profile may sit on its tiles.
Single pictures and grid-tiled photos, 4:2:0 and monochrome, 8- to 10-bit, alpha auxiliary images
(other auxiliary images — HDR gain maps, depth — are ignored), the container's rotation/mirror/crop,
ICC, EXIF and XMP, and the file's thumbnail item. 4:2:2 and 4:4:4 (Canon/Sony "HIF") are refused
with `Error::Unsupported`: heic-rs 0.1.1 loses sync on them. Read-only.
```rust
let info = lightcraft_heif::probe(&bytes)?; // size, depth, alpha: check limits first
let img = lightcraft_heif::decode(&bytes, &lightcraft_heif::Options::default())?;
// img.width, img.height, img.has_alpha, img.bit_depth, img.data (RGB/RGBA u16), img.colour, img.icc, img.exif, img.xmp
let thumb = lightcraft_heif::decode_thumbnail(&bytes, 256, &Default::default())?; // Option<Decoded>
```
Errors are `Error::Unsupported` (image sequences, overlays, 4:2:2/4:4:4, …), `Error::Limit` or
`Error::Malformed`. It never panics: every call into heic-rs runs under `catch_unwind`, and a panic
inside it (PhotoCraft's fuzzing found two in 0.1.1) becomes `Error::Malformed`.
Feature `testdata` exposes `lightcraft_heif::testdata`: lossless synthetic HEIF files (PCM-coded
32 × 32 HEVC pictures, grids, every property above) for the tests of the crates above.
## Why it is a separate, optional crate
- **A young decoder.** heic-rs is new and has a single maintainer. It is pinned exactly
(`=0.1.1`); moving the pin is a reviewed change (re-run the crate tests and
`cargo test -p lightcraft-codecs --features heif`). The other permissive candidates were
rejected: heif-oxide's HEVC decoder (rust_h265) follows FFmpeg's (LGPL) code structure, and
gamut-heic has no HEVC decoder of its own.
- **HEVC patents are a distributor's call.** `lightcraft-codecs` uses this crate only behind its
non-default `heif` feature; the apps forward it and the release packages enable it. Without it,
HEIC files are still recognised and opening one is a clear "HEIC/HEIF support isn't included in
this build" error — the same policy as PhotoCraft.
The crate depends on no other LightCraft crate; `codecs` → `heif` is the only edge between them.