43 Commits
Author SHA1 Message Date
NetterSilverandClaude Opus 5.5 03dd76022b Reject non-hex characters in engine hex color parser (#8541)
Found while testing crates/engine/src/commands.rs:283-291 (parse_hex)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:40:27 -04:00
NetterSilverandClaude Haiku 5.5 c1158f92e8 Accept all-caps possessives in spell check (#8628)
Found while testing crates/text/src/spell.rs:91 (Dictionary::check)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-23 17:40:22 -04:00
NetterSilverandClaude Haiku 5.5 45833ece7c Fix EngineData format_real emitting a bare trailing dot (#8486)
Found while testing crates/text/src/engine_data.rs:331 (format_real)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-23 17:39:13 -04:00
NetterSilverandClaude Haiku 5.5 010c542be4 Liquify: keep short strokes whole so undo removes only the last
Fixes #8055

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 03:38:51 +00:00
NetterSilverandClaude Haiku 5.5 8aa3b0668b Reject '+' signs in color picker hex field
Found while testing crates/ui-egui/src/color_picker_ui.rs:94-102 (parse_hex)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 01:43:02 +02:00
NetterSilverandClaude Haiku 5.5 67314ff606 Write DOMAIN_MIN/DOMAIN_MAX in the .cube writer
Found while testing crates/cms/src/lutfile.rs:227 (write_cube)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 00:46:33 +02:00
NetterSilverandClaude Haiku 5.5 b85b638e77 Keep '#' inside quoted .cube TITLE when parsing
Found while testing crates/cms/src/lutfile.rs:111 (parse_cube) and :227 (write_cube)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 18:15:46 +00:00
NetterSilverandClaude Haiku 5.5 acc3420c6d Keep previous crop length when normalizing rounds to zero
Found while testing crates/ui-egui/src/crop_size.rs:86-107 (format_length / normalize_length)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 20:14:50 +02:00
NetterSilverandClaude Opus 5.5 e86e6910ae fix(psd): bound the base style run a save copies per run
The base run comes from the file and is cloned once per character run, so
it now has to fit the template node budget, and each font is looked up
once per name. Also names the reopened-layer tuple in psd_kerning for
clippy::type_complexity.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 20:07:39 +02:00
NetterSilverandClaude Opus 5.5 20c9103148 fix(psd): write complete Txt2 style runs from the layer, number only file indices as kept
Photoshop reads the character style from Txt2 and quit on the bare run
(`/0 0 /11 mode`) that new objects got. New and edited objects now get one
style run per character run, built on one of the object's own runs with
every key kept, and font, size, faux styles, leading, scales, tracking,
fill colour, OpenType keys and auto-kern mode set from the layer. A font
the block's font list lacks is appended to it. Edited objects therefore no
longer keep the old text's features by position.

build_tysh no longer writes TextIndex 0 for a layer without one: the
export took it as a kept number, so a Type tool layer landed on object 0
(a deleted layer's, or the one of a layer above it). set_text_index puts a
missing TextIndex right before EngineData, where Photoshop writes it.

pad_frames pads to at most MAX_TEXT_INDEX + 1 frames.

edited_text_keeps_the_files_txt2_object (#7220) now expects style runs
that follow the layer's runs and size.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 19:48:40 +02:00
NetterSilverandClaude Opus 5.5 760109e23c fix(psd): give a new Txt2 object its own style and a number past the file's objects
A new object kept the template's style runs, and PhotoCraft's reader takes
font features from Txt2, so a new type layer came back with the template
layer's features (salt, ss01). Its style runs are now generated like the
stub's; only the template's structure is copied.

New type layers were numbered past the kept TextIndex values only, so after
deleting the layer with the highest index a new layer landed on its object
and took its style. They are now numbered past the file's Txt2 objects too.

txt2_extras_survive_a_resave_of_unchanged_text now gives its layer the TySh
index a file's layer has; without one the layer is new and no longer lands
on object 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 15:57:10 +02:00
NetterSilverandClaude Haiku 5.5 afeea2f643 Decode numeric character references in File Info XMP text
Found while testing crates/engine/src/file_cmds.rs:690 (xml_unescape), used by li_values, find_attr and read_file_info

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 13:42:22 +00:00
NetterSilverandClaude Haiku 5.5 ff2db1b83b Fix File Info showing 1/1 s for exposures just under one second
Found while testing crates/engine/src/file_cmds.rs:768

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 14:21:14 +02:00
NetterSilverandClaude Opus 5.5 304f055021 fix(psd): point a new Txt2 object's frame strike at its own frame
new_object copied the template's rendered strikes, whose frame strike
(/99 /F) still named the template's frame in /10. It now names the new
object's frame, like the view's /0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 14:04:33 +02:00
NetterSilverandClaude Opus 5.5 78cc36f24a fix(psd): keep preserved TextIndex values when a type layer is added below them
Text indices were assigned in one bottom-up pass, so a new layer took the
next free number before the layers above it claimed the numbers their TySh
keeps. Each of those was then renumbered onto its neighbour's Txt2 object
and took its style (70 of 74 layers on the #7698 file after adding a layer
at index 5). Kept numbers are now claimed first and new layers get numbers
past them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 10:51:26 +02:00
NetterSilverandClaude Haiku 5.5 e371bc34e3 Refuse strict .atn export of Apply Image with a blending mask
Fixes #7247

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 21:52:32 +00:00
NetterSilverandClaude Haiku 5.5 8de2db8764 Refuse strict ATN export of Select and Mask with brush strokes
Fixes #7539

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 23:42:10 +02:00
NetterSilverandClaude Haiku 5.5 a9df7b787b Refuse .atn export of crops with output size or resolution
Fixes #7191

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 23:25:37 +02:00
NetterSilverandClaude Haiku 5.5 35c7065692 Refuse .atn export of resolution-only Image Size without keepPrintSize
Fixes #7245

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:56:38 +02:00
NetterSilverandClaude Haiku 5.5 47f7c97a3b Refuse strict .atn export of a mask/channel-targeted Free Transform
Fixes #7195

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:48:58 +00:00
NetterSilverandClaude Haiku 5.5 48009ce53d Record one action call when playback pauses for a step dialog
Fixes #7365

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:40:02 +02:00
NetterSilverandClaude Haiku 5.5 8591ca1904 Scale layer-effect noise by coverage so it follows the glow
Fixes #7833

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:44:44 +00:00
NetterSilverandClaude Haiku 5.5 5a649f8e4e Apply background jobs to the layers they started on (#7620)
Fixes #7366

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-19 14:19:22 -04:00
NetterSilverandClaude Haiku 5.5 7b5f66be11 Don't paint from the sampled point when Alt is released mid-press
Fixes #7802

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:13:40 +02:00
2ef8a9d3f5 Reject exporting a partial Play Action call to .atn (#7602)
Fixes #7186

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-19 13:45:07 -04:00
NetterSilverandClaude Haiku 5.5 fe64e5a2bd Keep arbitrary canvas rotation interpolation in ATN export (#7630)
Fixes #7504

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-19 13:31:49 -04:00
NetterSilverandClaude Opus 5.5 604007490b fix(psd): replace an earlier save's Txt2 stub also when its text is edited
The stub filter applied only to the kept object, so an edited layer whose
slot held a stub from an earlier save went through edited_object and kept
the bare stub. The slot is now filtered before both lookups.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 15:33:05 +02:00
NetterSilverandClaude Opus 5.5 198fa59c7d fix(psd): a new type layer gets a full Txt2 object and its own frame (#7698)
A type layer the file's Txt2 has no object for (one added in PhotoCraft)
was written as a bare stub with no view, no paragraph runs and no frame
in /0 /8 /0. Photopea and Photoshop refused the file once the objects
outnumbered the frames.

build_txt2 now gives such a layer an object shaped like one of the
file's own (refitted with edited_object from #7220), with its view
naming its own frame, and pads the frame list to one per object. A stub
written by an earlier save is replaced the same way, so re-saving an
affected file repairs it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 14:56:15 +02:00
NetterSilverandClaude Haiku 5.5 92721dd8c4 Refuse strict .atn export of plain events whose target is not the layer pixels (#7564)
Fixes #7272

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 16:57:19 -04:00
NetterSilverandClaude Haiku 5.5 0807441e52 Make .pcraft reload f64 coordinates bit-exact (#7498)
Found while testing crates/format/Cargo.toml:19 (serde_json features), used for the manifest in crates/format/src/manifest.rs and store.rs

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 16:56:48 -04:00
7066497886 Keep fractional translation-only Free Transform on .atn import (#7401)
Fixes #7298

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:51:21 -04:00
NetterSilverandClaude Haiku 5.5 713dbbed2f Save Actions ATN files atomically so a failed write keeps the old file (#7403)
Fixes #7290

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 10:50:37 -04:00
NetterSilverandClaude Haiku 5.5 80553ecd93 Refuse strict ATN export of Close with an explicit document target (#7393)
Fixes #7299

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 10:50:32 -04:00
NetterSilverandClaude Haiku 5.5 866e7bfe4e Upload 16-bit layer masks as R16Float instead of R32Float (#6845)
Fixes #6534

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:34:37 -04:00
NetterSilverandClaude Haiku 5.5 dfb4aa70ae Keep Color Sampler points on their pixel after flips and turns (#6720)
Found while testing crates/engine/src/commands.rs:117-120 (turn) with crates/engine/src/canvas_geom.rs:224 (Turn::affine); applied in crates/engine/src/lib.rs:807-814 (Session::edit)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:34:32 -04:00
f6f53f657d Reject notes.set moves that make the popup non-finite (#6174)
Found while testing crates/engine/src/notes_cmds.rs:105

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:33:40 -04:00
NetterSilverandClaude Haiku 5.5 275d4cbcf7 Reject out-of-range leading, baseline shift and scales in type styles (#6196)
Found while testing crates/engine/src/type_cmds.rs:287

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:33:09 -04:00
NetterSilverandClaude Haiku 5.5 fb5896f43f Fix generator spaced size keeping size text in asset file name (#6628)
Found while testing crates/engine/src/web_cmds.rs:1171

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:07:45 -04:00
NetterSilverandClaude Haiku 5.5 e66941bde1 Ignore a leading UTF-8 BOM in variable data set CSV import (#6485)
Found while testing crates/engine/src/variables_cmds.rs:285-292 (import_data_sets_text; the file is read in import_data_sets at line 279)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:07:13 -04:00
NetterSilverandClaude Haiku 5.5 d722dd8b54 Clamp filter.cameraRaw exposure to its documented -5..5 range (#6876)
Found while testing crates/algo/src/camera_raw.rs:592 (value taken unchecked in crates/engine/src/lens_cmds.rs:137 raw_params)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:07:03 -04:00
NetterSilver 158dcc6731 Fix engine compile error: load export presets from presets JSON
Fixes #6911

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit bb7a5f2309)
2026-10-17 13:34:00 +03:00
NetterSilverandClaude Haiku 5.5 2466f5c3a7 Disable Convert to Smart Object for layers that are already smart objects
Fixes #6730

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 01:52:06 +02:00
NetterSilverandClaude Haiku 5.5 e5a4af7648 Find small objects in large documents with the Object Finder
Fixes #6576

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:44:00 +00:00