Commit Graph
104 Commits
Author SHA1 Message Date
.CooCoo 289dd0a874 Format: take the .pcraft envelope from craft-pcraft-format (#10724)
* Format: take the .pcraft envelope from craft-pcraft-format

The manifest envelope, TileRef, Hash, FORMAT_VERSION, EXTENSION, the
entry names, tile_path and blob_path, is_valid_hash, the manifest
nesting and item checks and the migration runner now come from
craft-libs' craft-pcraft-format. photocraft-format re-exports them, so
callers do not change. Manifest is craft_pcraft_format::Manifest<DocM>.

Saved bundles keep the same bytes. A save still checks only the nesting
and the item count of its manifest, not its size, and the manifest
nesting limit is still computed from photocraft_doc::MAX_GROUP_DEPTH.

Tests: a save, load and save again gives the same bytes in every color
mode and depth, with and without previews; MAX_GROUP_DEPTH equals
craft_pcraft_format::MAX_GROUP_DEPTH.

* Format: pin craft-pcraft-format from storytold/craft-libs

* Format: read manifests with craft-pcraft-format's read_manifest_with

Pins craft-pcraft-format to dca870a0, the head of craft-libs #407.
Loading reads the manifest with read_manifest_with, which runs the
limit check, the version check, the migration steps and the envelope
read in one path; the layers are still decoded one at a time after the
rest of the document. A save builds the manifest with Manifest::new and
tile references with TileRef::new, and the bundle's directory names and
the .zst suffix come from the crate's constants. Saved bytes and error
messages are unchanged.

* Format: pin craft-pcraft-format to craft-libs #407's head 04dd1bd

04dd1bd changes only the crate's docs and a test, so photocraft-format
builds the same code.

* Format: pin craft-pcraft-format to craft-libs main at b8f7d93

craft-libs #407 merged as b8f7d93. Its read_manifest also refuses a
thumbnail other than thumb.png and a composite other than
composite/preview.png, the only names photocraft-format writes.
2026-11-02 11:43:46 -05:00
Gabriel Heuser 24be8ea6e2 Add editable arrowheads to Line tool (#6408) (#9259)
* Add configurable arrowheads to line tool

* Add editable arrowheads to Line tool

* Fix arrow scaling validation and PSD import defaults

* Preserve arrow geometry under affine transforms

* Preserve scaled arrowhead dimensions and prevent non-finite geometry

* Localize arrowhead Start and End labels

* Fix arrow transform editability and short line handling

* Fix PSD arrow concavity serialization

* Fix arrow dimension fallback validation

* Refine arrowhead options UI to match Photoshop

* Add opt-in arrowhead defaults to Shape properties

* Fix tool reset syntax after upstream merge

* Validate arrowhead flags and clamp copied defaults

* Preserve editable headless lines under transforms

* Fix arrowhead UI imports and formatting after v0.17 merge

* Format arrowhead properties after v0.18 merge

* Fix Clippy lint errors in arrow geometry and tests

* Fix headless arrow geometry after nonuniform scaling

* Fix proportional arrow scaling in Properties panel

* Fix Rust formatting in Properties arrow scaling tests

* test: validate invalid arrowhead dimensions without mutation

* fix: preserve arrow compatibility with older pcraft versions
2026-11-01 18:46:05 -05:00
David Mann fea300dd4c Merge origin/main into integration batch 10 2026-10-30 01:47:01 +01:00
David MannandClaude Opus 5.5 ce33b19090 Tests: a failed autosave outcome test does not wait for a stuck write
Address CodeRabbit review: dropping the Autosaver joins its worker, which waits
for the write in progress, so a timed-out receive could still hold the test
until nextest kills it. The saver is now ManuallyDrop and only dropped on the
passing path. With a worker that sleeps 60 s per write and a 2 s bound, the
test fails after 2.01 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:15:31 +01:00
David MannandClaude Opus 5.5 f39f94aef8 Tests: the autosave outcome test waits up to 5 minutes, not 30 s, for a real write
background_save_outcomes_report_failure_then_recovery failed on main's Windows
integration job: the real (second) autosave write flushes every tile to disk and
took over 30 s on a busy runner (normally 2-3 s; a concurrent autosave test ran
past 60 s too). The bound only exists to turn a worker that never reports into a
failure instead of a hang, so it is now 5 minutes, still under the 10 minutes
after which nextest's ci profile kills a test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:53:19 +01:00
David Mann afacb057f7 Merge origin/main into pr-8571-fixup
Conflicts: svg.rs (main's bufread inflate and shared render helper, kept
with the PR's bounded raster path), psd_import.rs (the PR's vector
preview moved into main's smart_content), menus/invoke.rs (the SVG
intercept moved into main's split invoke_unguarded), rendering.rs and
the ui-egui import lists (main's explicit imports), Cargo.lock, docs
status lines (unions).
2026-10-29 16:38:24 +01: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
aiongg ae661394b2 Merge #9036: Autosave: replace a recovery sidecar in one step, so a listing never misses or doubles it (#9034) 2026-10-27 17:44:12 +00:00
aiongg 6e9fb30dbc Merge #6723: Color Lookup: PSD save keeps a .3dl/.look LUT file as loaded (#6544) 2026-10-27 17:44:05 +00:00
David Mann 2363c475c0 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/compose/src/lib.rs
#	crates/gpu/src/plan.rs
2026-10-27 14:17:25 +01:00
David MannandClaude Opus 5.5 c4b224b074 Merge main into fix/9034-autosave-discard
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 03:08:44 +01:00
David Mann cd485b6c2c Merge remote-tracking branch 'origin/main' into pr-7689-fixup 2026-10-27 01:54:27 +01:00
Don Omondi c129dd50e0 Merge main and preserve original-format embedded vector save-back 2026-10-27 00:45:48 +03:00
David Mann 7e4ceba5df Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/cms/src/lutfile.rs
2026-10-26 14:26:50 +01:00
NetterSilverandClaude Opus 5.5 92a1559138 Refuse .pcraft manifests with too many JSON values before parsing (#8893)
Fixes #8594

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 10:19:41 -04:00
David MannandClaude Opus 5.5 94244cf91a Address CodeRabbit review: check every autosave result and never hang the listing test
The writer thread now asserts each take_completed() result, so an earlier failed write
can't hide behind flush()'s last result, and a drop guard sets the done flag however the
thread ends, so a writer panic is reported by join instead of the listing loop spinning.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 13:09:17 +02:00
David MannandClaude Opus 5.5 c080783c00 Autosave: replace a recovery sidecar in one step, so a listing never misses or doubles it (#9034)
On Windows the recovery sidecar was written through store::write_atomic, which replaces the
old file with ReplaceFileW: it moves the old sidecar to a backup name first and only then moves
the new one in. A recovery listing in between saw the bundle without its sidecar and listed the
entry twice, or not at all (so a recovery prompt could miss a document). The flaky
autosave::recovered_entries_survive_a_second_crash_until_saved_or_closed on Windows CI was this.

The sidecar now goes through one AtomicFs on every platform whose replace is a plain rename
(one step); Unix keeps its 0600 temp file, Windows still refuses a read-only sidecar up front.
Recovery data is private to the app, so ReplaceFileW's ACL/stream preservation isn't needed.

Test: a_listing_during_an_autosave_sees_the_entry_exactly_once lists the recovery folder while
an autosaver rewrites the entry 200 times. With the old code it failed 3 of 3 runs on Windows
(two entries, once none); with the fix it passes 3 of 3.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 03:48:25 +02:00
David MannandClaude Opus 5.5 09d80b1a27 Move the frame-stroke tests into each crate's single test binary
Main now links each crate's integration tests into one tests/it binary;
the two new test files of this PR join it as modules.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 03:13:02 +02:00
David Mann 23d8f053cb Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/compose/src/shape_split.rs
2026-10-24 03:12:55 +02:00
David Mann feb20ebc60 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/gpu/src/plan.rs
#	crates/io/src/adjust_map.rs
2026-10-24 02:59:10 +02:00
David Mann c16f899467 Merge origin/main into fix/6544-lut-format-roundtrip
# Conflicts:
#	crates/format/tests/it/roundtrip.rs
2026-10-23 00:06:48 +02:00
David Mann fff01d8918 Integration: stack #7335 (its merge onto main, conflicts resolved) 2026-10-22 23:40:11 +02:00
David MannandClaude Opus 5.5 6c7e920d5a Merge PR #7335: Gradient Overlay: add Method selector and retain editable source stops
- crates/ui-egui/src/layer_style.rs: values_of keeps the PR's method/smoothness keys and source-stop ends, and main's (#7072) unconditional From/To and geometry fields.
- crates/compose/src/cmyk_tests.rs (no textual conflict): add the PR's new `interpolation: None` field to main's CMYK test GradientOverlay literal.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:39:14 +02:00
David MannandClaude Opus 5.5 cab3ef6191 Merge PR #5815: perf(doc): share the XMP packet, Duotone PSD data and unsupported adjustment bytes between snapshots
- crates/engine/src/tests.rs: kept both tests (main's restore_layer_selection test and the PR's history_states_share_large_document_payloads).
- crates/io/src/psd_import.rs: kept main's parsed Duotone inks (duotone_map) with the PR's Arc<[u8]> psd_raw; also main's unknown-adjustment-key import (#6575) now builds Arc<[u8]> raw.
- crates/io/tests/adjust_warnings.rs: moved to tests/it/adjust_warnings.rs on main; PR's .into() edits applied there, plus #6322's Color Lookup test (raw.as_slice().into()).
- docs/architecture.md: union; status line names both changes, both revision-history rows kept.
- Adapted main-new sites to the PR's types: psd_export.rs (Duotone write-back via as_deref/to_vec, Unsupported block compare by slice), inspect.rs and ui-egui unsupported_marker_tests.rs (raw .into()), io tests/it/psd_unknown_adjustment.rs (slice compare).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:38:56 +02:00
David MannandClaude Opus 5.5 95e0848332 Merge main into fix/4381-psd-frame-stroke
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:09:11 +02:00
David Mann 9487065314 Integration: merge main (one test binary per crate, #8644)
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/scorecard.md
#	scorecard/file_compat.toml
2026-10-22 19:55:06 +02:00
David MannandClaude Opus 5.5 f5533e5d82 Integration: merge main into batch 6
Main merged #5940, #6472, #7838 and #7922 directly. Kept from the batch:
the snapshot/History-follow identity at the history limit (#5940,
c7ef3676a; main still had the 3-tuple HistorySpot) and the strokeless
shape at a 0 px width step (#6472, 962539607; main still added the
stroke). Main already carries the other two fix-ups (34c9d0ea4, dff8bfd0e).

Overlaps with main resolved:
- #5842 vs main's #5568: one path, apply_color, tool-gated as #5842
  has it, with #5568's float fill, kept fill opacity and lock skip;
  shape_fill_ui's duplicate foreground_changed/gesture dropped; #5568's
  tests run with a shape tool.
- #6230 vs main's #5180: one Type tool path click (path_target), no
  second type.attachToPath; vertical type does not start type on a path,
  as main has it; main's path_at/path_cursor and canvas arm dropped.
- #5452 moved the shape swatch to shape_paint_ui.rs: main's hex field
  (#6201) ported there.
- type_extra_cmds::with_text takes main's dpi form, pub(crate) for
  type_area_cmds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:20:26 +02:00
aiongg a6428d3dfb Build each crate's integration tests as one binary
Every tests/*.rs file is its own executable that links the whole crate
graph. Move each crate's test files into tests/it/ as modules of one
tests/it/main.rs; helper modules under tests/common move with them.

These keep their own binary (own process):
- engine panic_hunt: a process-wide panic hook counts every panic.
- engine text_gamma: changes the process-wide text gamma.
- engine smart_filter_stages, mask_cache_purge: assert on global caches.
- codecs pnm_peak_memory: reads the process's peak RSS.
- photocraft mac_menu_appkit: harness = false.
2026-10-22 16:55:34 +00:00
David MannandClaude Opus 5.5 7a54fa9c77 Integration: merge main into batch 6
Conflicts, both sides kept: main's .act swatches next to the batch's .asl
styles (Open filters, preset extensions), main's Render smart filters next
to the batch's Distort ones (53 mapped), parity doc status lines.
docs/scorecard.md regenerated.

Follow-ups the merge needed: the Distort smart filter readers pass their
enum type to main's stricter enum_name (the type their writers use), and
the CMYK effect tests set main's new StrokeFx overprint and Bevel
gloss_anti_alias.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 12:09:25 +02:00
Yonghyuk Choi dc029b93c5 Merge main into Gradient Overlay method branch 2026-10-22 12:38:20 +09:00
aiongg 2c2269ff0b Merge PR #5421: fix(format): serialise directory bundle saves with a bundle-wide lock
crates/format/src/store.rs: kept both field sets in PcraftWriter::default (main's blob_hash_cache/compressed_budget and the PR's lock_wait) and both setters (set_compressed_cache_budget, set_lock_wait).
2026-10-22 02:24:47 +00:00
aiongg d71ff0d34d Merge PR #7580: Preserve saved PCraft previews when manifest replacement fails 2026-10-21 21:55:49 +00:00
David Mann a8f91f54ad Merge PR #6230: feat(type): area type, text that wraps inside a closed path or shape
Integration: resolve with main for area type (#6230)

- Image Size with a new resolution (#7124, canvas_geom::set_resolution) now scales an area type's
  path with the text space like a box or a type path, so the same words wrap onto the same lines;
  test a_resolution_change_keeps_area_type_wrapping_where_it_was fails without it.
- The Paragraph panel's justify buttons (#7713) stay available on area type, which is paragraph
  text in Photoshop; test justify_buttons_work_on_area_type.
- Test files: main's tests plus #6230's; layout.rs imports joined; docs and scorecard regenerated.
2026-10-21 23:46:05 +02:00
aiongg 94d28535d3 Merge PR #6464: Survive a lost window GPU device: draw nothing, save unsaved work for recovery, close (#3438, #1215) 2026-10-21 18:15:02 +00:00
aiongg 77557d75f1 Merge PR #8229: Integration batch: 8 PRs on main
# Conflicts:
#	crates/engine/src/layer_style.rs
#	crates/io/src/psd_export.rs
#	crates/io/src/smart_map.rs
#	docs/file-format-parity.md
2026-10-21 15:45:07 +00:00
Rene Leonhardt df6a7e7b5a perf(format): reduce ZIP archive allocations
Reserve complete bundles and directories from compressed sizes, and borrow
UTF-8 entry paths in the lookup index. Preserve lossy names and first-entry
lookup for duplicates.

Check ZIP field lengths before writing, bound metadata reservations, and
cover byte equivalence, overflow and incremental saves. ZIP entry paths
have a format limit independent of filesystem path constraints.
2026-10-21 13:59:34 +02:00
David Mann a492716367 Merge PR #5990: Bevel & Emboss: keep the Gloss Contour's Anti-aliased (antialiasGloss) 2026-10-21 11:29:05 +02:00
David Mann 14b928e8a8 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-21 10:56:06 +02:00
David Mann d25387a459 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-21 09:35:08 +02:00
aiongg fc371711e6 Merge PR #5847: Shapes: Density and Feather on shape layers (#5846)
# Conflicts:
#	docs/scorecard.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-21 05:04:03 +00:00
0073b395d4 Integration: merge main, resolve conflicts (#5990)
docs/file-format-parity.md: main added three 2026-10-15 revision rows
(DDS save, PNG sTER, PSD guides) where the PR added its own; keep all four.

Co-authored-by: varanus-salvator <262257003+varanus-salvator@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 23:50:13 +02:00
David Mann 2adfe0c4e2 Merge PR #5807: Type: keep superscript and subscript when a text layer is re-rendered (#5645) 2026-10-20 22:39:12 +02:00
David Mann 0b39361076 Merge main into feat/tool-214-12-shape-feather 2026-10-20 17:12:29 +02:00
00xJ0 abd3755d41 RecoveryStore::flush keeps each entry's key, so a later discard still removes it (#6464 review) 2026-10-19 12:05:01 -07:00
PanPDX 54b6b0dbc0 Merge remote-tracking branch 'upstream/main' into area-type
# Conflicts:
#	crates/ui-egui/src/type_tool.rs
#	docs/gaps.md
#	docs/scorecard.md
#	docs/target-app-parity.md
2026-10-18 22:41:59 -07:00
00xJ0 7bb7819b00 Lost window device: close only once every unsaved document is saved for recovery, retrying every 2 s; also check the device on the screen-picker frame (#6464 review) 2026-10-18 17:15:13 -07:00
jonathnwxh 86b4c67adf Expect post-commit best-effort preview cleanup on Unix 2026-10-19 05:37:19 +08:00
jonathnwxh 9c927993b5 Preserve omitted PCraft previews until manifest commit 2026-10-19 05:29:30 +08:00
Finn NewickandClaude Opus 5.5 e795cabc79 test(format): skip the bundle-lock test only where file locks are unsupported
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:16:37 +01: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