Commit Graph
169 Commits
Author SHA1 Message Date
David Mann f162c19e81 Merge remote-tracking branch 'origin/main' into integration-batch-17
# Conflicts:
#	crates/ui-egui/src/control/dispatch.rs
#	crates/ui-egui/src/control/params.rs
2026-11-05 12:44:02 +01:00
Khawar Zamman Wani 9a390661b5 PSD: flat files keep their spot and alpha channels (#10260)
Thanks @wanikhawar — merging.

**Summary:** Flat PSD import now keeps spot/alpha channels. Alternate Spot Colors (resource 1067) fills in spot inks when DisplayInfo uses an undocumented space; `alpha_channel_names()` centralizes name reads; new `psd_flat_spot_channels` integration tests cover the path.
2026-11-05 12:22:45 +01:00
yoriswind 1720af269d Merge current main while preserving recorded Batch safeguards 2026-11-04 10:47:01 -08:00
David MannandClaude Opus 5.5 cbc674ea9a Fix-up for #10837: score legacy names in linear time
The position checks of the codepage guesser (letters after a character, a closing !,
the Cyrillic run around a letter) rescanned the rest of the name from every non-ASCII
character, so a hostile .atn or PSD with a 64 KiB step name of one letter kept Load
Actions busy for about three minutes. Each is now found once per name; the three
measured cases take 0.03 s together, and a regression test covers them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 12:54:55 +01:00
yoriswind 85fc78bb64 Merge current main into recorded Actions dialog support 2026-11-03 21:55:00 -08:00
Trevor BrownandClaude Fable 5.1 037a8c5167 Load Actions: a lone Cyrillic letter after a digit never counts, and ¡ counts only where it opens an exclamation closed by "!"
Review: Mac Roman "90°" alone has no ASCII letter, so its one windows-1251 letter made the name
"mostly Cyrillic" and the fallback showed "90Ў"; "¡Ánimo!" counted nothing for windows-1252 since
only ASCII letters were counted after ¡; and Mac Roman "20 °Celsius" tied with windows-1252
"20 ¡Celsius". A lone Cyrillic letter right after a digit never counts (a run after a digit, "5шт",
still does); the letters after a character include accented ones; and ¡ counts where it opens an
exclamation, two letters or more after it and the closing "!" later in the name, which the degree
sign before a unit never has.

Re-lands 47ee3f696, which went out under another PR's message by mistake and is reverted just
before this, with one test case less: without any hint a lone Mac Roman degree sign before an ASCII
letter is also a Big5 punctuation pair, a tie the fallback flags, so the Mac Roman cases keep their
Latin hints.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-03 19:11:04 -05:00
Trevor Brown f3ce2e2b9e Revert "Gradient Overlay drag: no drag on an empty layer, and the origin follows the selected instance"
This reverts commit 47ee3f6960.
2026-11-03 19:07:10 -05:00
Trevor BrownandClaude Fable 5.1 47ee3f6960 Gradient Overlay drag: no drag on an empty layer, and the origin follows the selected instance
Review: an empty layer gave bounds of 0 x 0, so the canvas took the drag from the Hand tool and
wrote offsets of up to ±4 layer widths from a short drag, for a gradient that paints nothing;
and the drag's one origin stayed when `selected` changed under a held press, so the next instance
moved from the previous origin and the whole travel since the press. `gradient_layer_bounds`
returns `None` for empty bounds, and `__gradientDrag` keeps the instance id, the origin and the
pointer total at that point, taken afresh when the id differs: offsets are the origin plus the
travel since.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-03 18:55:03 -05:00
Trevor BrownandClaude Fable 5.1 f80955ce0d Load Actions: a lowercase rare letter opening a word counts for windows-1252, and so does ¡ opening a word
Review: "šuma" (0x9A u m a) read as Mac Roman "öuma", certain, where main tied it and read
windows-1252; and "¡Hola!" read as Mac Roman "°Hola!". The word-initial rule for windows-1252's
0x80–0x9F letters no longer asks for a capital (the file's own alphabet still decides: a file that
writes ö and never š reads the byte as Mac Roman ö), and ¡ counts as common text for windows-1252
where it opens a word of two letters or more (`opens_word`, in `score` and in the final
windows-1252/Mac Roman comparison), while Mac Roman's degree sign on the same byte, after a
number ("Rotation 90°") or before a single letter ("20 °C"), stays as it was.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-03 17:47:32 -05:00
Trevor BrownandClaude Fable 5.1 946d2d9c7b Load Actions: an all-caps word-initial Š or Ž counts for windows-1252, and a digit before a Cyrillic run glues it
Review: "ŠKODA" (a capital before an ASCII capital) counted for nothing and could read as Mac
Roman "äKODA"; Mac Roman "Layer 90°é" read as windows-1251 "90ЎЋ", two Cyrillic letters right
after a number. The word-initial rule now takes an ASCII letter of either case after the capital,
and `cyrillic_word` treats a digit before the run as glue (a digit after still isn't: "Слой1").
Main's new fallback test tied Mac Roman "Ändern" with windows-1251, which this branch settles for
Mac Roman; it ties "éäé" with "ЋЉЋ" instead and checks "Ändern" is certain.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-03 16:55:18 -05:00
Trevor BrownandClaude Opus 5.5 c0b23817d6 Merge upstream/main into fix/atn-mac-roman
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:43:47 -05:00
David MannandClaude Opus 5.5 72c2585177 Merge origin/main (287352bf92) into integration-batch-13
Conflict in crates/engine/src/jobs.rs: main's save commit point (#5333,
OPEN/COMMITTED/CANCELLED phase) met the batch's cancel state
(CANCEL_REQUESTED/WORK_FINISHED). Both now share one atomic with a
COMMITTED bit; commit vs cancel and the batch's late-cancel guard each
stay one compare-and-swap. A Batch that refuses a repeated or late cancel
reports CancelRefused::Finishing ("finishing") in jobs.cancel's
notCancelled list, still {"cancelled": 0}. control-protocol.md documents both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 19:35:44 +01:00
David Mann 7329c700bb Merge remote-tracking branch 'origin/main' into integration-batch-13
# Conflicts:
#	apps/photocraft-cli/src/args.rs
#	crates/engine/src/jobs.rs
#	crates/engine/src/jobs/tests.rs
2026-11-03 13:52:30 +01:00
FredApps afa0a86341 psd: widen staged RLE data to PSB in short reads, never reading it back whole 2026-11-03 13:06:09 +01:00
FredApps 2bad559628 psd: copy source-backed channel and merged data through in short reads
A channel or merged image still in its source (an imported file's, or one
spilled to scratch) is copied to the output in 8 MiB pieces instead of being
read whole into memory first.
2026-11-03 10:33:52 +01:00
FredApps 05fc07b538 Merge main into fix/save-memory-6607
Resolve against main's save restructure (Services::save_file/SaveCtl, scratch-integrity checks,
ZipWriter::with_entries, exact encoded_len):
- PSD/PSB saves stream the file model through atomic_write_stream_progress; the length used for
  progress and reservations is main's exact encoded_len (the PR's size_bound under-counted lazy
  data); export_with/encode_with share checked_stages, so main's scratch checks (previews
  included) still refuse unreadable scratch.
- Drop ZipWriter::for_entries in favour of main's with_entries.
- TIFF: take_from_psd moves layer data out of the export's own model (never the document);
  body() reserves its exact length, failures are OutOfMemory (not LimitExceeded, which would
  trigger the PSB retry).
- Streaming writer: AlreadyExists from the writer is a failed save, not a name collision.
- Remove dead Vec put_widened_rle; channel_data_len is test-only.
2026-11-03 09:23:16 +01:00
David Mann 2f84f55158 Merge #10832: ATN: keep encoding fallbacks among the top-scoring candidates 2026-11-03 00:30:50 +01:00
yoriswind 3d5a42e3bb Merge current main before Batch review repairs 2026-11-02 12:29:16 -08:00
Trevor BrownandClaude Fable 5.1 d75b2ab512 Load Actions: the file's own alphabet settles a word-initial capital, and a digit doesn't glue a Cyrillic word
A rare windows-1252 capital starting a word counts unless the file's Unicode text writes the Mac Roman letter on that byte and never this one (état, über); Слой1 reads as a Cyrillic word. Tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 07:24:05 -05:00
Trevor BrownandClaude Fable 5.1 80ba6fc873 Load Actions: Cyrillic words and word-initial Š/Ž count by their position, and a Latin hint no longer rules windows-1251 out
A Cyrillic step name in a Latin-hinted set (Ёлка in a French set), a Cyrillic word beside a Latin one (Layer Слой) and a windows-1252 name starting with a capital Š or Ž (Škoda) all read as before; the Mac Roman cases of #10774 still read as Mac Roman. Tests for each.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 06:05:50 -05:00
Trevor BrownandClaude Fable 5.1 f0f80c016a Load Actions: Mac Roman step names with accented letters or a degree sign read as Mac Roman (#10774)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 05:24:32 -05:00
neversaynv3r c335153361 ATN: keep encoding fallbacks among the top-scoring candidates 2026-11-02 18:21:32 +09:00
yoriswind efccb678d8 Fix Batch regression compilation and document admission boundaries 2026-11-01 17:39:05 -08:00
David Mann 5bc852379a Merge PR #10743: Read Photoshop Actions version 12 descriptors
With our fix-up 1f524c378b on top of the author's head 713aa92ba5. Resolved with main: the version check sits in main's parse_layout (it merged cleanly); doc comments combined; atn_contract no longer expects version 12 to be refused and pins that an empty version 12 set parses; one ATTRIBUTION row for all ATN fixtures; the fixture README states which files were encoded how; development.md no longer counts the fixtures.
2026-11-02 02:13:56 +01:00
yoriswind c78b84a1cd Port CSH import backend while retaining recorded shape IDs
Port the ten backend, automation and test paths from #5493 by
@jonathanwxh-cell, pinned at 43920ab780.
Keep its original CSH codec, bounded preset reader and protection tests.
The prerequisite's UI, translation and parity-document changes are excluded.

Adapt ShapePreset construction to retain the exact source identifier. Empty
identifiers remain anonymous presets; repeated identifiers resolve when their
geometry is identical and refuse resolution when it conflicts. Add one
import-to-ATN Shape Blur regression and document the source attribution.

Original contribution: https://github.com/storytold/photocraft/pull/5493
Source-only integration; compilation and combined runtime validation remain.
2026-11-01 17:01:17 -08:00
aiongg fab871dadb Merge pull request #10535 from davidmann4/integration-batch-11
Integration batch 11: 9 ATN PRs on main
2026-11-01 19:11:02 -05:00
yoriswind 4c6ddb9cb7 Correct legacy action import expectations and document version support 2026-11-01 11:49:17 -08:00
yoriswind 7ca16e9eba Read Photoshop Actions version 12 descriptors 2026-11-01 11:45:32 -08:00
5f63b3fe4c Integration: address CodeRabbit review of batch 11
- #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>
2026-11-01 17:51:02 +01:00
Khawar Zamman WaniandFredApps 209bce8d46 Budget PSD pattern expansion and bound multichannel conversion (#10541)
* Stream PSD user and real masks into tile rows

* Correct streamed-mask fixture metadata and test lint issues

* Budget PSD pattern expansion and bound multichannel conversion

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-01 16:00:21 +01:00
7e50896afb Integration: drop the glued-letter rule again (#8327)
The previous fix-up counted a letter glued to an ASCII letter as common
only when it was Latin. That turned ordinary windows-1251 names such as
"CMYKканал" or Ukrainian "Копiя" (Latin i) into a windows-1252 (or GBK)
reading of the whole set, with no warning, where the PR read them right.

Back to the PR's scoring for single-byte pages; the ¥ removal stays.
windows-1252 "Fläche m²" / "Preis £5" reading as windows-1251 is the
PR's own known limitation, now noted in the code. A Russian set plus
"CMYKканал" is pinned as windows-1251.

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:35:14 +01:00
bd04a88292 Integration: keep Mac Roman bullets and Latin words out of the wrong page (#8327)
Mac Roman 0xA5 is the bullet, windows-1252 0xA5 is ¥: with ¥ counted in
the windows-1252 re-weigh, Mac "Ebene • Kopie" read as "Ebene ¥ Kopie".
Drop ¥; the other kept symbols are no letter or typographic mark in Mac
Roman.

windows-1251 has І і д where windows-1252 has ² ³ ä, so "Fläche m²" read
as "Flдche mІ" (already so in the PR head; main showed it right). In a
single-byte page, a letter glued to an ASCII letter now counts as common
only when it is a Latin letter. Real Cyrillic names ("Новый слой",
"Копия слоя 2", "Канал RGB") still read as windows-1251. "Preis £5"
(Ј between a space and a digit) still reads as windows-1251; documented.

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:19:58 +01:00
1d0bc23c3e Integration: don't count symbols on Mac Roman letters as windows-1252 (#8327)
The previous fix-up counted § ® ¾ ¿ (and ¹ » ¼ ½) as common windows-1252
text, but those bytes are Mac Roman ß Æ æ ø (π ª º Ω). Mac names with no
Unicode copy such as "Weiß", "Gaußscher Weichzeichner", "Størrelse",
"Lærredstørrelse" and "Æble" then tied and read as windows-1252 ("Wei§",
"St¿rrelse"), where the PR read them right.

Keep only the 12 symbols whose byte is not a letter in Mac Roman
(¡ ¢ £ ¥ © « ° ± ² ³ ¶ ·). Windows "Größe »", "50 °" and "« auto »" still
read as windows-1252; a name whose only non-ASCII character is ® ("Logo
®") reads as Mac Roman "Logo Æ" again, as on the PR head (tested as a
known limitation).

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:00:36 +01:00
af59f65b82 Integration: keep windows-1252 symbols in .atn step names (#8327)
The code-page guess counted only letters and typographic marks as common
text in single-byte pages, so a Windows step name with no Unicode copy and
a Latin-1 symbol read better as Mac Roman, whose letters sit on those
bytes: "Logo ®" showed as "Logo Æ", "Größe »" as "Grˆfle ª" (main showed
them right), and Save Actions wrote that text back.

When the guess lands on Mac Roman, weigh it against windows-1252 once more
with common Latin-1 symbols (© ® ° § « » ± ½ …) counted and the letters
windows-1252 has only at 0x80-0x9F left out. Mac Roman keeps the names
only when it still reads better; a tie goes to windows-1252, confident
with a Latin hint and flagged uncertain otherwise. Mac Roman "Größe",
"Ändern", "Contrôle", "Arrière-plan" and the corpus French sets still read
as Mac Roman.

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:43:03 +01:00
David Mann d86f678325 Merge main into #8327 2026-11-01 14:27:37 +01:00
Khawar Zamman Wani 97a83f074f Bound PSD layer and mask import memory before decoding (#10503)
* 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)
2026-11-01 12:33:09 +01:00
Ben Huyck d8244139bc Actions: read .atn step names in the code page Photoshop wrote them in (#6743) 2026-10-30 09:43:49 +00:00
Ben Huyck fe7f48fe2e PSD: guess the legacy code page of 8-bit names (#6743) 2026-10-30 09:43:49 +00:00
Dylan M. Taylor ba25f585bd Refactor psd for strict Clippy checks 2026-10-27 23:47:06 +00:00
David MannandClaude Opus 5.5 5ccb6fb723 Merge main
Conflicts with main's batch #9880:
- psd file.rs / layer.rs: #5287 (PSB by encoded size, RLE tables widened on
  promotion) against #6583's lazy reader. Main's new widening and length code
  read `.data`, which #6583 leaves empty while the bytes stay in the source;
  it now goes through `encoded()` / `encoded_len()` (also the auto-merged
  lines in `rle_widening`, `encoded_len` and `LayerRecord::write`), and the
  lazy reader sets `write_as_psb: false`. New test
  `a_lazy_psd_promotes_to_the_same_psb_as_an_eager_one`: a lazily read PSD
  writes the same PSB bytes as an eager one; it fails with a `.data` read.
- direct_select.rs / vector_ui.rs: #9321's Type Path and #6353's hidden
  Work Path both kept.
- io tests main.rs: both modules. scorecard.md regenerated (12 of 181);
  ui-parity.md and gaps.md follow it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-27 19:49:42 +01:00
David Mann 3a689f217c Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/engine/src/file_cmds.rs
#	crates/engine/src/retouch_cmds.rs
#	crates/engine/src/vector_cmds.rs
#	crates/io/src/psd_export.rs
#	crates/io/src/psd_import.rs
#	crates/io/src/smart_map.rs
#	crates/psd/src/layer.rs
#	crates/raster/src/lib.rs
#	crates/ui-egui/src/camera_raw_ui.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/filter_dialog.rs
#	crates/ui-egui/src/gpu_canvas.rs
#	crates/ui-egui/src/panels.rs
#	crates/ui-egui/src/retouch_ui.rs
#	crates/ui-egui/src/transform_tool.rs
#	crates/ui-egui/src/vector_ui.rs
#	docs/gaps.md
2026-10-27 14:26:26 +01:00
David Mann c14a707d2a Merge PR #6583: PSD/PSB open without reading the whole file: channel data read as decoded, in bands into tiles (#5106)
Merged at the fix-up commit before its main merge (362947695d); the
conflicts with the batch are resolved here: psd_import.rs keeps both
sides' tests, tiff_layers.rs takes ImageData::new.
2026-10-27 13:50:37 +01:00
362947695d Integration: a source read error in the layer records fails the open (#6583)
The lazy parse took any error from read_layer_info on a Layr/Lr16/Lr32
global block as a damaged block and dropped the layers. A failed read of
the source (PsdError::Read: a dropped network share, a file rewritten
while it opens) then let a 16/32-bit layered file open silently from its
merged image, with no damage warning, and a save replaced its layers.
A read error now fails the parse, as reading the whole file would.

The new test fails each read of a clean parse once, in turn, and checks
the parse either fails with the read error or matches from_bytes; with
the fix reverted, read 20 of the Lr16 sample drops the layers silently.

Found by CodeRabbit's review of the PR.

Co-authored-by: ptrinh <774083+ptrinh@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:28:32 +01:00
David MannandClaude Opus 5.5 f428433ccb Merge main into fix/psd-size-encoded
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:59:27 +01:00
aiongg 1f0d1a4ef3 refactor(psd): move tiff.rs's transcode module to tiff/transcode.rs 2026-10-26 22:54:56 +00:00
aiongg 02d2de4b99 refactor(psd): move patterns.rs tests to patterns/tests.rs 2026-10-26 22:30:12 +00:00
aiongg 363a5797f8 refactor(psd): move compression.rs tests to compression/tests.rs 2026-10-26 22:30:11 +00:00
aiongg d314299d5b refactor(psd): move layer.rs tests to layer/tests.rs 2026-10-26 22:30:11 +00:00
aiongg 35107dccae refactor(psd): move tiff.rs tests to tiff/tests.rs 2026-10-26 22:13:07 +00:00
aiongg 5286968033 refactor(psd): move abr.rs tests to abr/tests.rs 2026-10-26 22:13:07 +00:00