Commit Graph
190 Commits
Author SHA1 Message Date
FredApps 07ae59b628 Merge pull request #9745 from vangel76/perf/9741-psd-zip-predict
perf(psd): single-pass 16/32-bit ZIP prediction encode and decode
2026-11-07 15:39:45 +01:00
David Mann b28b2f665e Merge pull request #8633 from cloutier/feat/psd-animation-parser
feat(psd): parse legacy frame-animation metadata
2026-11-07 14:11:59 +01:00
6326117c53 Web build: big operations that won't fit fail with an error instead of trapping, and a trap says so (#10129)
* Raster: ask the allocator whether a big operation fits; PSD save reserves its whole output

New photocraft_raster::headroom: ensure(need) tries to reserve the need plus a margin and frees it
at once (web only; native always passes), below(bytes) tells whether less than that can be
allocated, and simulate_available fakes the answer for tests and diagnostics.

PsdFile::to_bytes reserved only the pixel data, so embedded smart-object data and other tagged
blocks grew the output by doubling, which on the web is one unrecoverable huge realloc. It now
reserves the exact encoded length.

* Big operations that won't fit in memory fail with an error instead of trapping

Place, Image Size, a smart-object re-render and Save now ask the allocator whether their estimated
need can be allocated before they start (photocraft_engine::memory_gate, estimates per operation,
photocraft_io::estimate_export_bytes for saves). A refusal changes nothing and says what the
operation needed and what to do (save, Edit > Purge > All, close documents).

A standing notice warns when less than 512 MiB can be allocated, with hysteresis, so the user can
save before anything traps. Notices can now be sticky, which keeps them past the auto-hide delay.

* Web build: a trap says so instead of freezing the page, and ?free-mb simulates low memory

index.html holds a hidden, static 'PhotoCraft stopped' message with a Reload link. web.rs reveals
it when the module traps (the window error event, or an unhandled rejection from a spawned
future), tells running out of memory from an internal error by the panic message a chained panic
hook kept, and skips the Leave site prompt once stopped. ?free-mb=N makes the memory gates and the
low-memory warning see only N MiB, for checking them in a browser.

* Docs: web build memory handling in the gaps list and the parity assessment

* Engine: use is_multiple_of in the megabyte formatter

* Cargo.lock: the web shell depends on photocraft-raster

* Web boot page: carry the stopped message too, as the test that keeps the two pages equal requires

* Save check counts one copy of the document, and runs once per save

The encoded file's buffer is reserved fallibly, so a save it doesn't fit
in fails with an error instead of trapping; counting it as well refused
saves that would have fitted. On the background-save path the check ran
in write_document and again in start_save, which other callers reach
directly; it now runs only in start_save there.

* Review fixes: warning check allocates nothing, PSD merged image counted, automation saves checked

The low-memory warning's periodic check reads the size of linear memory
instead of reserving a block: wasm memory never shrinks, so a trial every
few seconds raised the high-water mark by up to 768 MiB for nothing. The
operation checks keep their trial reservation.

PSD and PSB saves always build a canvas-sized merged image (a placeholder
without maximum compatibility) and hold it raw and encoded; the save
estimate now counts it. The synchronous automation save checks memory
before encoding, as File > Save does, and its test asserts the memory
error.

The trap listeners go in before the app is built, so a trap while
building it shows the stopped message too, and a memory access out of
bounds reads as unexpected rather than as running out of memory.

* Cover layered PSD preflight limitation

* Fix layered PSD test iteration

* Docs: layered PSD preflight limitation in the gaps list

* Web OOM gate: gate direct exports, truthful advice for unbounded PSD sources (#10024)

* Web OOM gate: estimate layered PSDs per layer instead of refusing every real PSD

The PSD check admitted a file only when its color-mode data, image
resources and layer section were all empty. Every Photoshop file has
image resources (at least the resolution), so on the web nearly every
real PSD was refused for Place, PSD smart objects could not render,
and Image Size was refused for documents holding one, whatever the
free memory (u64::MAX never fits).

The color-mode data and image resources hold no pixels, so they are
now only skipped. A layered file reads its layer count from the layer
info (signed, absolute value) and adds a canvas-sized surface and mask
per layer to the flat estimate. Files that are not 8-bit RGB or
grayscale, keep their layers in a Layr tagged block, or whose sections
can't be read stay unbounded and refused, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Web stopped page: match trap messages ignoring case

Safari reports the allocation-failure abort as "Unreachable code
should not be executed" and Firefox says "out of memory", which the
case-sensitive matching missed: the trap was not recognised, or was
shown as an unexpected stop instead of running out of memory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export estimate: count the merged image OpenRaster writes

The ORA writer keeps the layers but also flattens the document for
mergedimage.png, a 16 B/px composite of the canvas, which the
estimate left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:04:59 +01:00
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
David MannandClaude Opus 5.5 16000b01ef Address CodeRabbit review: batch 17 findings
Engine: droplet dependency capture skips disabled steps; a nested Batch
that was cancelled or could not write its error log fails the caller;
runDroplet forwards overrideOpen; actions.rename follows named Batch
steps; Batch steps inside a script count against MAX_SCRIPT_STEPS;
output claims compare destination identity; Save and Close never
replaces a read-only source. ATN: Md must be a BlnM enumeration,
adjustment-layer names must round-trip, Calculations exports a missing
blending as Multiply, Apply Image refuses unnamed-layer transparency.
Filters: Shape Blur records its resolved geometry, reserves its kernel
memory first, and reports a preparation failure as an error, not a
cancel; Crop keeps an artboard preset when the size is unchanged and
fits the board on a turned crop.

Codecs/cms/algo: zero-axis FITS image HDUs are empty; a GIF walk that
breaks off before the trailer fails closed; two-value .3dl shaper rows
are applied; fragmented custom kernels are refused and their work polls
cancellation.

UI: Conditional branches play through panel playback; paused actions
refuse to resume after being replaced; Playback Options OK validates
its fields; transform double-click ignores a hidden pivot; path boxes
snap to a stationary selection; modal blocking uses the effective tool;
a picker-consumed release clears snap lines and ends a Move drag; the
Crop preset control shows Selection and checks only it; Crop box undo
restores frame_from_selection; Bosnian fill labels.

Tests: timing asserts moved to an ignored test, plus the review's
coverage nitpicks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 11:37:38 +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
Vincent Cloutier 0d7e849605 Merge current upstream main and require decoded animation corpus descriptors 2026-11-02 14:37:22 -05: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
1f524c378b Integration: track the v12 .atn fixtures and sniff v12 in the CLI (#10743)
The three version 12 fixtures were tracked inside crates/psd/fuzz/corpus,
which crates/psd/fuzz/.gitignore ignores and cargo-fuzz rewrites (cmin) or
deletes; the psd and engine test binaries include_bytes! them, so cleaning
the corpus broke the build. They move to crates/psd/tests/fixtures/atn with
a README (sizes, purpose, sha256; the seeds note folded in) and an
ATTRIBUTION.md row; the fuzzer takes the folder as an extra corpus dir.

photocraft-cli recognised an extensionless Actions file only by version
word 16, so a version 12 set without .atn (classic Mac OS Photoshop 5)
went down the JSON path and failed with a UTF-8 error. It now accepts 12
and 16, the versions photocraft-psd reads. Input: v12-commands.atn copied
to "Legacy Actions" and passed to load_actions_file.

Co-authored-by: yoriswind <164435053+yoriswind@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 02:09:41 +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
David Mann bb8edaf596 Merge PR #8327: Actions: read .atn step names in the code page Photoshop wrote them in (#6743)
# Conflicts:
#	contributors/people.toml
#	crates/engine/src/cmd/atn_cmds/tests.rs
2026-11-01 15:36:45 +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
5ff10e120d Integration: keep the NaN-safe .atn fuzz invariant (#7561)
The previous fix-up put main's atn fuzz target back. It compares the
parsed actions with assert_eq!, so any valid file holding a NaN double
fails the fuzzer falsely (NaN != NaN); the PR's own contract test
nan_payloads_signed_zero_and_infinities_survive_without_false_fuzz_failures
covers exactly that. The target now calls the shared check again, at its
new path under tests/it/common.

Co-authored-by: denstu473 <63150090+denstu473@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:30:55 +01:00
David Mann d86f678325 Merge main into #8327 2026-11-01 14:27:37 +01:00
4b053e15ae Integration: keep the ATN contract tests, drop the extra workflow (#7561)
The contract tests no longer compiled on main (AtnItem::dictionary is now
Vec<u8>, so it is compared with b"Future event"), sat outside main's
tests/it layout, and the new atn.yml added six legs (two macOS) to every
PR against ci.yml's policy. Move the tests into tests/it so the existing
CI runs them, drop atn.yml and docs/atn-testing.md, keep main's ci.yml and
fuzz target, and note the committed fixtures in ATTRIBUTION.md.

Co-authored-by: denstu473 <63150090+denstu473@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:25:51 +01:00
David Mann 893d12bee2 Merge main into #7561 2026-11-01 14:19:49 +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
vangel76 a3f9d7e8d8 Merge upstream/main into perf/9741-psd-zip-predict 2026-10-29 20:40:22 +01:00
Dylan M. Taylor ba25f585bd Refactor psd for strict Clippy checks 2026-10-27 23:47:06 +00:00