mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-14 19:26:51 -04:00
bd632e7eb33c601fbeee7aa19c77b1859f02a7e7
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd632e7eb3 |
Layered TIFF: open and save Photoshop layer data in TIFF files, in either byte order (part of #215) (#672)
* Layered TIFF: open and save Photoshop layer data in TIFF files, in either byte order (part of #215) Photoshop keeps a layered TIFF's layers in two private tags: 37724 (ImageSourceData, the same layer section a PSD has) and 34377 (the image resources). PhotoCraft now reads and writes both, so a TIFF opens with its groups, masks, layer styles, type, shapes, smart objects and adjustment layers exactly as the PSD path would, and saves them back. * photocraft-psd: a `tiff` module with `ImageSourceData` (parse/write, PSD- and PSB-sized), the 34377 resource helpers, and a field-by-field byte-order transcoder. In Intel-order TIFFs Photoshop byte-swaps the whole block structure (reversed keys, little-endian integers and doubles) while pixel samples stay big-endian; the transcoder knows the layer-info structure, masks, blending ranges and every block photocraft-io maps (descriptors, TySh, lrFX, the binary adjustments, paths, patterns, filter effects, metadata settings, linked layers, annotations...), recognizes descriptor-shaped unknown blocks, and drops the rest with a warning instead of passing byte-swapped data to other readers. The reader gained an optional little-endian mode. 23 unit tests; a fuzz target in the CI matrix. * photocraft-codecs: the two tags travel as opaque bytes on `Metadata`, read by a bounds-checked walk of IFD0 (classic and BigTIFF, both byte orders) and written back as BYTE / UNDEFINED tags. `tiff_writes_little_endian()` tells which order the encoder produces. * photocraft-io: `tiff_layers` rebuilds a PSD model from the TIFF's pixels plus the tags on import, and on export runs the PSD exporter (new `merged_matte` / `merged_compression` options), interleaves its merged planes for the TIFF image and stores the layer section in the encoder's byte order. `ExportOptions.tiff_layers` (default on). Lab and Multichannel documents save flat; extra alpha channels are not written (one transparency sample). * UI: the TIFF Options prompt ("Including layers will increase file size." / "Discard Layers and Save a Copy" / "Don't show again") behind Preferences > File Handling > Ask Before Saving Layered TIFF Files; `ExportSettings.tiff_layers`; catalogs updated. * Tests: io round trips at 8/16/32 bits in Gray/RGB/CMYK, equivalence with the PSD path, every TIFF compression, the flat fall-backs, malformed input, and files written by psdtags in both byte orders (fixtures from scripts/layered_tiff_fixtures.py); a corpus test (feature `corpus`) writes every corpus PSD as a layered TIFF and compares the result with the PSD round trip (700 files, 0 differences, 0 crashes). Codecs tests cover the tag walk on hand-made files. * Scorecard FILE-215-7 done, BUG-204-3 partial; README and book updated. Co-Authored-By: Claude Mythos 5.1 <[email protected]> * Layered TIFF: de and pt-br strings; neutral wording in the psd tiff docs The four psdtags fixtures stay out of the repository (no binary test data here): the generator now writes them to the gitignored corpus/layered-tiff/, and the tests that read them skip with a message when absent. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Regenerate docs/scorecard.md Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: leon <[email protected]> Co-authored-by: Claude Mythos 5.1 <[email protected]> Co-authored-by: Brandon Thomas <[email protected]> |
||
|
|
47f9306fd0 |
Open HEIC/HEIF photos (#355) (#372)
* 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 <[email protected]> * 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 <[email protected]> * 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 <[email protected]> * 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 <[email protected]> * 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 <[email protected]> * Docs: HEIC open is an optional build feature, on in official builds Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> Co-authored-by: Brandon Thomas <[email protected]> |
||
|
|
a8afec4455 |
Open documents in bounded reads, with a clear out-of-memory error (#375) (#401)
Every open path read the whole file with std::fs::read, which asks Windows for up to 4 GiB in a single ReadFile. Some file systems (exFAT, network redirectors) reject a read that large with ERROR_INVALID_PARAMETER, "The parameter is incorrect" (os error 87), as reported for a 4.75 GB PSB in #375. Add photocraft_format::read_file and read_all beside atomic_write: 64 MiB reads into a buffer reserved up front, and an OutOfMemory error that says how much the file needed. Route every document read through them: - the background open job (engine jobs.rs read_path); - the engine's read_file; - Open Recent and OS open events; - desktop drag and drop, which now goes through open_path (and so through the background job when jobs are on); - the File > Open dialog; - .pcraft loading; - the automation workspace read and automation::files::open; - smart object Replace Contents and linked files. The dialog no longer fails silently: PickOpenFn returns the picked name with the read result, and a failure is reported through open_failed and the notices like any other open failure. Speed is unchanged (1.11 s vs 1.13 s for a warm 4.75 GB file). Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
d2576b27eb |
Profile mismatch: compare profiles by colour, not bytes (#394)
Opening any file Photoshop tagged with sRGB IEC61966-2.1 asked "Embedded Profile Mismatch: sRGB IEC61966-2.1 vs sRGB IEC61966-2.1": open_policy compared a hash of the ICC bytes, and Photoshop's v2 profile (1024-entry tables) and the built-in v4 sRGB (parametric curves) are the same colours in different bytes. 32-bit documents in Photoshop's linear sRGB missed the stay-linear exception for the same reason. Add Profile::same_colors: same colour space and every sample of a device grid within dE76 0.5 through both (re-encoding costs 0.025; moving the red primary 2% costs 1.0). Colours are compared rather than round-tripped because CMYK -> PCS -> CMYK is not an identity even for one profile. Of the 75 profile-tagged PSDs in the test corpora, all 75 prompted on open; now 6 do (Adobe RGB, Gray Gamma 2.2, SWOP), each a real mismatch. Co-authored-by: Claude Opus 5.5 <[email protected]> |