Preserve the target-only call and exactly reconstruct empty-guide settings. Apply preset tags without resizing, retain fractional RGB, and refuse unresolved guide state before mutation. Nonempty associations and unproved flag values remain unfinished.
- #8714: a Camera Raw Filter step imports only with a process version
the PSD mapping has verified (PrVN/PrVe 5/184549376 or 6/251920384)
and a CrVe text; other steps stay kept steps that save back unchanged.
- #7642: the patternName fallback matches names only, so a pattern
whose id equals that text no longer wins. A step that names its
pattern only by patternName exports that name.
- #8327: the iso-2022-jp label is refused (its names are 7-bit escape
sequences that would pass through as ASCII).
- #10417: the Levels export gate also refuses endpoints of the wrong
shape (both ends text, a text gamma) and channels that aren't objects.
- #10459: a set paused at a step dialog keeps the rest of the set by
action name, so actions.move while the dialog is open neither plays a
foreign action nor skips one; "Played N steps" covers the whole Play
(steps before the pause and the dialog's own step); the suggested .atn
name is cut to 255 bytes at a character boundary; actions.list returns
every set, empty ones too; set_names dedups with a HashSet.
Co-authored-by: FinnNk <1424666+FinnNk@users.noreply.github.com>
Co-authored-by: Silvertree2010 <133535268+Silvertree2010@users.noreply.github.com>
Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-authored-by: marshiyar <57055687+marshiyar@users.noreply.github.com>
Co-authored-by: hectorviov <1501713+hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#8327 adds `AtnFile::encoding`. Two tests from other PRs in the batch
build an AtnFile literal without it (#8714 fix-up's Camera Raw save-back
test, #8858's Vibrance string-class test), so the engine's lib tests
didn't compile on the batch. They now fill the rest with
`..Default::default()`, as the other literals in the file do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: main moved crates/engine/src/atn_cmds.rs into crates/engine/src/cmd/atn_cmds/; the refusal is ported into steps_make.rs set_to's layer.setAdjustment arm unchanged. The tests followed the rename.
`resolve_or_named` resolved the recorded `Idnt` with `resolve`, which also
matches by name in each collection. So a document pattern named like the
id beat the library pattern with that id, and a foreign id equal to some
pattern's name (`Idnt "Red"`, `Nm "Blue"`) played "Red" and never tried
the recorded name. The id is now looked up by id only (document, then
library), then the name decides. A library pattern found by id whose
pixels can't be read reports that instead of falling back, main's
paintable check still runs, and a pattern installed neither way is named
in the error (`no pattern "My Wood" (id "...")`) instead of only its UUID.
Co-authored-by: Silvertree2010 <133535268+Silvertree2010@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vibrance's adjustment class is now Photoshop's string id `vibrance`, so Set and Make steps
save back with the class Photoshop runs instead of the `Vbrn` code it refuses (#8383).
`Vbrn` moves to LEGACY_CLASSES, so actions saved before still load. A recorded Vibrance
with non-zero temperature or tint stays a kept step and saves back unchanged.
Co-authored-by: jturnbach <70334515+jturnbach@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A loaded Camera Raw Filter step became an import-only filter.cameraRaw, so
Save Actions dropped it (skipUnsupported) or failed, where before it was
written back byte for byte. Keys outside the table (e.g. PerV = 20, a
profile name) were ignored, so the step replayed a different look without
being reported.
The step now keeps its recorded descriptor in a hidden param and saves back
as that descriptor while its params are still what it imports as; edited or
PhotoCraft-recorded steps are still refused. A step with any unknown key, or
with no settings, stays a kept Photoshop step, as the PSD mapping does.
Co-authored-by: FinnNk <1424666+FinnNk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bound PSD import pixel storage before decoding
* Include ZIP inflater workspace in PSD preflight
* PSD import: budget unknown-mode layers, stop after a fatal layer error, keep best-effort for non-allocation limits (#8593 review)
- free_group's brush check builds the set of group names once instead of
scanning every preset for each numbered candidate.
- reimporting_a_gradient_file_asks_before_touching_its_group covers the
gradient branch of the prompt: no prompt for a new group, Cancel imports
nothing, Import as New Group adds "Fire (2)", Replace swaps "Fire" alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Importing an .abr or .grd whose name matched an existing group silently
deleted that group's user presets (edited or moved-in ones included); the
preset libraries are outside document history, so it could not be undone.
- brush.presets.importAbr / gradient.presets.importGrd: `replace` now
defaults to false; a taken group name imports beside it as "Kit (2)",
"Kit (3)"…, and the result's `group` names the one it landed in.
- UI: when the group already holds the user's presets, a prompt asks
Import as New Group (default) / Replace (can't be undone) / Cancel.
Agents drive it with ui.dialog.set {"choice":"replace"} / confirm / cancel.
- The status bar names the group the file landed in.
Fixes#10640
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty set made with New Set lasted only the session, and Save
Actions… on it failed with "no actions in a set named …". Photoshop
saves an empty set to the .atn, and the ATN writer handles a set with no
actions, so `actions.save` now writes it; loading such a file brings it
back as an empty folder (once, however often it is loaded). Saving every
action with none is still refused, as is a set that doesn't exist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A set name with surrounding spaces comes from a Photoshop .atn (load
keeps the file's name) or an older actions.json, and New Action records
into such a set under that exact name. `actions.save` trimmed the name
it was given and then compared exactly, so Save Actions… on that set
failed with "no actions in a set named …". It now takes an existing
set's exact name, as `actions.record` does, and trims any other.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Artboards share one canvas, so a layer dragged from one board onto another in
the Layers panel (layer.moveTo, including the Alt-drag copy) changed parent but
kept its old canvas position, outside the board it now belonged to, and the
board clipped it away.
apply_move now shifts a layer that lands on a different board by the offset
between the two boards' origins, through move_layers (the Move tool's path).
Reordering within a board, leaving or joining a board from the top level,
position-locked layers and moving a board itself are unchanged. The Layers
panel's drop preview uses apply_move, so it shows the same result.
Locks are read before the drop as well as after, so a layer whose position
was locked only through the board it left stays put (review follow-up).
Co-authored-by: Claude <noreply@anthropic.com>
The author's main merge brings one new test (full coverage keeps Threshold over
extreme float channels) and rewords the #9483 tone comment; its main side
(b1cfff9d3) is already in the batch. Docs keep the batch's newer status lines and
revision rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Channel targeting routes an allow-list of pixel-editing paint commands, not every
`paint.*` id: the Mixer Brush's Alt-click load and Symmetry no longer follow a colour
set or get refused with "Rasterize the layer" on a fill layer. Patch and Content-Aware
Move stay routed (#9274).
- Native vector save-back checks the preview SVG as strictly as stored previews are
checked on load and PSD export, so a preview with an unreadable embedded image is
refused instead of stored and later dropped (#8571).
- .pcraft blobs read their zstd frame with framing headroom, so an incompressible
preview right at its 16 MiB limit still loads; the limit still bounds the data.
- Levels/Curves recall (Alt+shortcut) decides the combined Lab record from the target
the dialog captured, as remembering does, so a viewed layer mask keeps its settings
beside a Lab colour set (#9274).
Each comes with a test that fails without it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Photoshop's Actions panel has a folder button and a New Set… menu item that make an
empty action set (default "Set 1"); New Action lands in the selected set. PhotoCraft
showed sets from Load Actions but couldn't make one.
- actions.newSet: an empty set (default "Set N"), kept for the session until it
holds an action; actions.record takes a `set` for the new action.
- Actions panel: the folder button and New Set… open a name dialog; empty sets show
as folder rows; a click on a folder row selects it; New Action records into the
selected action's set, else the selected set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Photoshop opens the Stroke dialog for a Stroke descriptor without its blend
mode, even with dialogs off, so an exported action stopped there. stroke_to
now writes edit.stroke's defaults for location (center), opacity (100),
mode (Normal) and preserveTransparency (false) when the step leaves them out,
as Photoshop's own recorded Stroke carries them all.
Fixes#8303
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
layer.setAdjustment changes only the settings it names, but the Levels
descriptor writes each range whole and fills the end an edit did not name
with 0 or 255. A recorded {"kind":"levels","inBlack":31} was exported as
Inpt [31, 255] with nothing skipped, so replaying it also reset a retained
Input White. This is the Levels half of #8701 (Color Balance and
Hue/Saturation, #8531).
levels_complete accepts a Levels edit only when, for the master curve and
every channel object, inBlack/inWhite are both given or both absent, and
likewise outBlack/outWhite. set_to uses it as the levels arm of the
existing completeness check, so strict export refuses the step and a
non-strict export lists it as skipped.
Test partial_levels_edits_refuse_strict_export fails without the fix (the
export succeeds with Inpt [31, 255]) and passes with it.
Fixes#8530