mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-29 12:27:38 -06:00
* 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>
35 lines
2.1 KiB
Markdown
35 lines
2.1 KiB
Markdown
# photocraft-heif
|
|
|
|
The optional HEIF/HEIC decoder of PhotoCraft: iPhone and Mac photos. A thin, panic-guarded wrapper
|
|
around [`heic-rs`](https://github.com/tbraun96/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.
|
|
|
|
```rust
|
|
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-run `cargo fuzz run decode_heif` in
|
|
`crates/codecs` and `cargo 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-codecs` uses this
|
|
crate only behind its non-default `heif` feature; 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`).
|