* Open HEIC/HEIF photos (#355) iPhones save HEIC by default and Photoshop opens it; PhotoCraft had no HEIF code, so .heic was missing from File > Open and failed to decode. Add Format::Heif to photocraft-codecs, decoded by heic-rs (pure Rust, forbid(unsafe), MIT OR Apache-2.0, wasm-ready): single pictures and grid-tiled photos, 8-bit to U8 and 10/12-bit to U16, auxiliary alpha, ICC, EXIF and XMP. The container's irot/imir/clap are applied and EXIF Orientation is rewritten to 1, so photos are never turned twice. Limits are checked against the declared size before decoding. Read-only (no pure-Rust HEVC encoder), listed in ASYMMETRIC_EXCEPTIONS. File > Open (desktop, web) and the batch list accept heic/heif/hif. Tests compare against Apple's own decode and a 16-bit source, cover orientation, metadata, limits and every truncation; fixtures from heic-rs and pillow-heif are attributed in ATTRIBUTION.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * HEIF: pin heic-rs exactly and add a decode_heif fuzz target Review follow-up: heic-rs is young and parses untrusted files, so pin it (=0.1.1) and fuzz the HEIF path. The target covers both orientation paths and is meant to run with -timeout so a hang is reported, not only a panic. It is added to the CI fuzz matrix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * HEIF: a heic-rs panic is a malformed-file error, not a crash Fuzzing decode_heif found two out-of-range slices in heic-rs 0.1.1 on malformed files: - in its box parser (boxes.rs:130), reachable from a 72-byte file, even through the metadata-only probe; - during HEVC reconstruction (hevc/decode/recon.rs:70). The background job path catches panics, but the synchronous ones (jobs off, the CLI) did not. The HEIF codec now runs the decoder under catch_unwind and reports a panic as CodecError::Malformed, as gpu/health.rs already does around wgpu. The fuzz target also calls heic-rs directly, so its panics still reach the fuzzer. The 72-byte input is a regression test, which fails without the guard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * HEIF: move the decoder into an optional photocraft-heif crate The heic-rs decoding from #372 now lives in `crates/heif` (photocraft-heif, standalone, depends only on heic-rs =0.1.1): probe, decode with a pixel limit, container transforms, alpha, 8/10-bit, ICC/EXIF/XMP and the catch_unwind guard, behind a small API of its own (Info, Options, Decoded, Error). photocraft-codecs uses it behind a new non-default `heif` feature; the apps and photocraft-io forward it. HEIF detection, extensions and mime stay compiled in, so without the feature a HEIC file is still recognised and opening it is a clear "HEIC/HEIF support isn't included in this build of PhotoCraft" error. `cargo xtask layers` allows exactly codecs -> heif between standalone crates. The fixtures are no longer committed: `cargo xtask corpus --heif` fetches them from heic-rs (tests/fixtures, v0.1.1) and pillow-heif (tests/images) at pinned commits, verified against xtask/heif-corpus.sha256 (same bytes as the PR's copies). The fixture tests run with `--features corpus,heif` (`cargo xtask test-corpus` enables both). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Build CI and official binaries with HEIC support (--features heif) CI test and clippy, the FreeBSD job, and the macOS, Linux (and Flatpak), FreeBSD, Windows and web packaging all build with the `heif` feature; CI also tests codecs/io without it on Linux so the "not in this build" path stays covered. `cargo xtask wasm` also checks photocraft-codecs with `--features heif`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: HEIC open is an optional build feature, on in official builds Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||
| README.md | ||
README.md
photocraft-heif
The optional HEIF/HEIC decoder of PhotoCraft: iPhone and Mac photos. A thin, panic-guarded wrapper
around heic-rs, a pure-Rust HEVC still-picture decoder
(no unsafe, MIT OR Apache-2.0): single pictures and grid-tiled photos, 8- and 10-bit (10-bit
decodes to 16-bit), alpha auxiliary images, the container's rotation/mirror/crop, ICC, EXIF and XMP.
Read-only: writing would need an HEVC encoder.
let info = photocraft_heif::probe(&bytes)?; // size, depth, alpha: check limits first
let img = photocraft_heif::decode(&bytes, &photocraft_heif::Options::default())?;
// img.width, img.height, img.has_alpha, img.sixteen_bit, img.data (RGB/RGBA), img.icc, img.exif, img.xmp
Errors are Error::Unsupported (image sequences, overlays, …), Error::Limit or
Error::Malformed. It never panics: every call into heic-rs runs under catch_unwind, and a panic
inside it (fuzzing found two in 0.1.1) becomes Error::Malformed.
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-runcargo fuzz run decode_heifincrates/codecsandcargo xtask test-corpus). - HEVC patents are a distributor's call. HEVC is patent-encumbered in some jurisdictions, so
whether a build includes an HEVC decoder is a build-time choice.
photocraft-codecsuses this crate only behind its non-defaultheiffeature; the apps forward it (cargo build -p photocraft --features heif). Official PhotoCraft builds and CI 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 crate depends on no other PhotoCraft crate and knows nothing of photocraft-codecs' types;
codecs → heif is the one allowed dependency between standalone crates (cargo xtask layers).
Tests on real files live in photocraft-codecs (tests/heif.rs, features corpus,heif, files
fetched by cargo xtask corpus --heif).