mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
* craft-heif: stills decode at the size the container declares A coded HEVC picture is a whole number of coding blocks and can be larger than the image the container's ispe declares (Sony codes 1920x1080 as 1920x1088 without a conformance window). decode returned the coded size, so probe and decode disagreed and the padding rows showed as a dark band. decode_item now crops to ispe before the alpha merge and the transforms, measures the clap parity on the declared size, and compares the alpha item's declared size with the picture's instead of the coded planes. A declared size larger than the coded picture is Malformed. Ported from storytold/lightcraft#3977. * craft-heif: read_metadata reads the primary image's EXIF and XMP without decoding Cataloguing a photo needs its EXIF and XMP, not its pixels. read_metadata opens the container under the same panic guard and box census as probe and returns what decode would attach. Ported from storytold/lightcraft#2087. * craft-heif testdata: Spec::stereo builds a spatial photo (grpl/ster entity group) A second image of the primary's size and a ster entity group naming both, so callers can test stereo detection on a file this crate decodes. Ported from storytold/lightcraft#1684. * craft-heif: put_alpha uses is_multiple_of --------- Co-authored-by: Mason <mason276752@gmail.com> Co-authored-by: jkalkstein <76634771+jkalkstein@users.noreply.github.com> Co-authored-by: Mitch Lindgren <mitch@lindg.ren>
54 lines
3.3 KiB
Markdown
54 lines
3.3 KiB
Markdown
# craft-heif
|
||
|
||
An optional HEIF / HEIC decoder for iPhone and Mac photos, shared by LightCraft and PhotoCraft. It was moved from
|
||
LightCraft's `lightcraft-heif`. [`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 = craft_heif::probe(&bytes)?; // size, depth, alpha: check limits first
|
||
let img = craft_heif::decode(&bytes, &craft_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 = craft_heif::decode_thumbnail(&bytes, 256, &Default::default())?; // Option<Decoded>
|
||
let (exif, xmp) = craft_heif::read_metadata(&bytes)?; // no picture decoded: for cataloguing
|
||
```
|
||
|
||
Chroma is upsampled like libheif by default.
|
||
`craft_heif::Options { chroma: craft_heif::Chroma::Apple, ..Default::default() }` matches Apple's
|
||
decoder (and so Photoshop on macOS) instead; the two differ only next to sharp colour edges, where
|
||
Apple's blends the neighbouring column and, for 4:2:0, the neighbouring row.
|
||
|
||
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 `craft_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.4`); moving the pin is a reviewed change (re-run the crate tests and each app's HEIF tests,
|
||
e.g. `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.** Apps use this crate only behind a non-default
|
||
`heif` feature, which their release packages enable. Without it, HEIC files are still
|
||
recognised, and opening one gives a clear "HEIC/HEIF support isn't included in this build" error.
|
||
|
||
The crate depends on no other Craft crate.
|