The warning triangle on a comp row sent layerComp.updateWarnings
{"clear":true}, which dropped the stale states of every comp. The
command now takes an optional "comp" (id or name) that limits both the
report and the clear to that comp; an unknown comp is an error and
changes nothing. Without "comp" it still acts on every comp (Clear All
Layer Comp Warnings). The row icon sends its own comp id.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* File Handling: wire Image Previews to embed a PSD thumbnail (#204)
Preferences > File Handling > Image Previews is live for PSD/PSB saves. With
Always Save (the default) and Ask When Saving, the file carries Photoshop's
thumbnail image resource (1036: the 28-byte kJpegRGB header and a JFIF stream,
at most 160 px on the long side); Never Save writes none. The thumbnail is the
reduced composite converted to sRGB through the document's profile with
photocraft-cms (8/16/32-bit; Gray, CMYK and Lab become RGB), over white where
transparent. Ask When Saving has no Save As checkbox yet, so it saves the
preview, as Photoshop's checkbox starts on.
The preference reaches Save, Save As, Save a Copy and automation saves in the
app (ExportSettings.image_previews), and the engine's headless saves
(file.saveACopy, batch, Layers/Comps/Artboards to Files) through SaveOpts.
photocraft_io::ExportOptions gains image_previews (default on).
Settings that do nothing: 32 of 153 (#204).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* File Handling: rustfmt the Image Previews save path
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Applying a comp after ordinary edits now backs up the edited layout instead of keeping
a stale one; cycling or reapplying unedited comps keeps the original backup. The check
runs only on comp application and respects each comp's capture flags. Fixes#919.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comp positions were computed with unchecked i32 arithmetic on values from
files: import added a layer's origin to the cmls `Ofst` (and truncated wider
integers with `as i32`), export subtracted the origin from the stored
position, and applying a comp subtracted the current position. Extreme values
panicked with overflow checks on and wrapped otherwise.
Import now keeps offsets at i64 and drops a position whose sum does not fit,
with an import warning; export omits an `Ofst` that does not fit; applying a
comp skips a move that does not fit. Visibility of the same entries is kept.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Maintainer decision on #672: the app's Save As keeps TIFF layers as Photoshop does (it sets
ExportOptions.tiff_layers from its Layers option), but scripted and agent saves stay flat by
default so conversions keep predictable sizes. #672 merged with the default on, so every
headless TIFF save became layered.
- photocraft-io: ExportOptions::default() has tiff_layers: false. The desktop and web Save As
already set it explicitly from their settings, so the app is unchanged.
- photocraft-cli: --tiff-layers on convert, run and batch (listed in the usage text).
- engine: file.saveACopy, Batch, Image Processor, the export-to-files commands and the lens
batch take "tiffLayers": bool=false, through one SaveOpts { quality, tiff_layers }.
- automation: serve doc.save and MCP doc_save take tiffLayers (default false).
- Tests: default ExportOptions write a flat TIFF; the CLI writes flat without the flag and
layered with it (run and convert); #672's layered-TIFF tests ask for layers explicitly.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Every unwrap/expect/unreachable in non-test engine code now returns an
EngineError (or a predicate's Err string) or uses a real fallback:
- enabled predicates read the active layer through active_layer_of()
instead of unwrap() after has_layer();
- new raster layers get their pixels through pixels_mut()? instead of
surface_mut().expect("raster");
- layer paths use split_last().ok_or(..)? (Merge Down, Arrange, Ungroup,
Release Clipping), Auto-Align/Auto-Blend/Photomerge carry placements
instead of re-unwrapping them, and "next free name" searches are bounded;
- web export builds its options map directly, quantize_rows has a wasm
tail, parse_script rejects non-array/object JSON, the shape-layer edit
returns an error instead of unreachable!, and the gray composite
profile falls back to sRGB.
The engine denies unwrap/expect/panic/unimplemented/todo/unreachable.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
CI's `cargo fmt --all -- --check` has failed on every run because the
repo had no rustfmt config and was never formatted. Use the same settings
as EffectCraft/FilmCraft (max_width 160, use_small_heuristics Max), which
also keeps the churn small. Formatting only; no code changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>