mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-26 02:59:17 -06:00
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>
48 lines
3.0 KiB
Markdown
48 lines
3.0 KiB
Markdown
# 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.
|