Commit Graph
2534 Commits
Author SHA1 Message Date
David MannandClaude Opus 5.5 bf80e2d2fa Select and Mask: Shift Edge is a curve on coverage, so hard edges stay put
#5176 made ±100% move the edge by max(radius, feather, 2σ smooth), at
least 1 px. Measured in the reference application (a 100 px square,
Radius/Feather/Smooth each varied, Shift Edge -100/-50/+100):

- A hard selection does not move at all, at any Shift Edge.
- On a feathered edge the result is a fixed per-pixel curve, the same at
  2, 5 and 10 px feather: the pixel's odds a/(1-a) are multiplied by
  49^(shift/100). At -100% a 50% pixel becomes 2%, at -50% 1/8, at
  +100% 98%. The fit holds within ±0.05 in log-odds on every sample.

So Shift Edge is now that curve, applied last as before. It needs no
neighbours, so the morphology callback and the halo/spread it added are
gone, with the ignored benchmark that timed it (matting::morph itself
stays for Select › Modify and the mask view).

Tests: a hard edge is unchanged at ±50/±100%; seven measured
before→after coverage pairs; a feathered edge is pulled in; the engine
refine tests now check the hard edge stays and a feathered one moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:58:18 +01:00
FredApps 722a9bd5cf Merge current main and remove app-local integration workflow additions 2026-10-30 12:22:42 +01:00
Dylan M. Taylor 382b047c30 Merge pull request #10223 from FredApps/ci/test-runtime-2026-10-29
test: partition long parity matrices without dropping cases
2026-10-30 07:12:16 -04:00
FredApps 0f120bbda1 Merge current main, reconcile streamed PNG profiles and workflow inputs 2026-10-30 06:52:05 +01:00
Dylan M. Taylor 249d126626 Update prompt shows the app icon and accent color instead of a letter (#10243)
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#2f7bf5, its colour in ArtCraft Launcher). The updater, the self-update
helper and craft-update's startup prompt all get them through crate::UPDATE_APP; the
prompt draws the icon, the accent and "by ArtCraft" (craft-update's default developer).

craft-update is pinned to storytold/craft-libs main at 1065653e7 (#434).
Clippy fixes for Rust 1.99 in untouched code (same logic):
- apps/photocraft/src/app_dirs.rs
- crates/codecs/src/codecs/via_image.rs
- crates/engine/src/canvas_geom/tests.rs
- crates/ui-egui/src/panels/blend_preview.rs
2026-10-30 01:27:27 -04:00
FredApps a4ab4873e8 Merge current main, retain full-sweep and new benchmark inputs 2026-10-30 03:05:00 +01:00
aiongg 7d66766afb Merge pull request #10157 from FredApps/integration/reviewed-performance-2026-10-29
Integrate 16 reviewed performance and UI fixes
2026-10-29 21:07:40 -04:00
FredApps 0cb4ec56d3 Merge current main and complete retained Pen messages in Nordic catalogs 2026-10-30 00:48:24 +01:00
FredApps c8c8fc7821 Reduce repeated GPU setup and UI work; partition remaining regression matrices 2026-10-30 00:39:19 +01:00
Dylan M. Taylor 6fdd6bb1b7 packaging: Flatpak finds and prints to CUPS printers (#10196)
* packaging: Flatpak finds and prints to CUPS printers

The Print dialog listed no printers in the Flatpak: the runtime has libcups but not
lpstat/lp, the sandbox couldn't reach the CUPS socket, and driverless network printers
(lpstat -e) need Avahi. Bundle lpstat/lp/lpoptions from CUPS 2.4.20 (Apache-2.0,
statically linked, licence installed) and grant --socket=cups and
--system-talk-name=org.freedesktop.Avahi in both manifests.

* print: lp takes the job only when CUPS lists a printer; the only printer by default; ~/.cups read-only

Review (CodeRabbit) on bundling lp in the Flatpak:
- With lp present but CUPS down or empty, the job failed on lp instead of reaching the
  IPP route and the print portal. lp_route now gives up the route when lpstat lists no
  printer, before anything is submitted.
- With no printer named, no default and one queue, IPP picked it but lp failed. lp_route
  names the only printer.
- The sandbox ignored the user's default printer, saved options and client.conf server:
  grant ~/.cups read-only in both manifests.

* print: no printers for lp means the portal, not IPP; bounded listing; CUPS socket wrapper

Review:
- When lp is there but CUPS lists no printer, the job went to the IPP route, whose
  server detection ignores ~/.cups/client.conf and could print to a local default
  printer instead of the configured server. It now goes to the print portal, or fails
  with no portal.
- The lpstat listing before a job is bounded (10 s, then lp takes the job as before)
  and runs outside SPOOLER, which guards only Windows driver calls.
- Flatpak mounts the host's CUPS socket at /var/run/cups/cups.sock whatever path
  client.conf or CUPS_SERVER names; the CUPS tools now run through a wrapper that
  points a socket path missing in the sandbox there, leaving server names alone.

* packaging: redirect a custom CUPS socket only when it is the one Flatpak mounted

Review (CodeRabbit): Flatpak picks the socket it mounts at /var/run/cups/cups.sock
with stricter rules than CUPS (flatpak-run-cups.c: a socket CUPS_SERVER, else the
first line spelled exactly "ServerName /path" in ~/.cups/client.conf, else the
default), while CUPS reads the keyword in any case and takes the last ServerName. The
wrapper now redirects only when CUPS' socket is the one Flatpak chose, so a job can't
reach a different server; otherwise CUPS fails on the missing path.

* print: a printer listing past its deadline kills and reaps lpstat

Review: the 10 s limit stopped waiting but left a hung lpstat and its thread
running, so repeated print attempts could pile them up. photocraft now runs the two
lpstat listings itself (craft-print's lpstat_command and an equivalent lpstat -e,
parsed by printers_parsed) and kills and reaps each one at the shared deadline. The
output is read on a thread that ends with the process, so nothing outlives the job.

* packaging: never redirect a CUPS_SERVER the sandbox was given

Review (CodeRabbit): Flatpak picks the socket it mounts from the host's CUPS_SERVER,
so one set by flatpak run --env or an override may not be what it mounted. The
wrapper now leaves any CUPS_SERVER alone and redirects only a client.conf socket that
matches Flatpak's choice; otherwise CUPS fails on the missing path instead of
reaching a different server.

* packaging: point CUPS at the mounted socket only when it is the one Flatpak chose, else fail

Review (CodeRabbit): with a custom socket listed first and the default last in
~/.cups/client.conf, Flatpak mounts the custom one at /var/run/cups/cups.sock while
CUPS picks the last line, finds that path, and talks to the custom server. The
wrapper now compares CUPS' socket with Flatpak's choice even when the path exists:
equal, CUPS is pointed at the mount; different, the tool fails with an error instead
of reaching another server.

Also (CodeRabbit):
- A printer named in the job goes to lp even when CUPS lists none: listing can be
  forbidden while printing is not, and the portal can't honour a name.
- A failed lpstat -e (CUPS unreachable, listing forbidden) means the list can't be
  told, so lp takes the job, instead of an empty list sending it to the portal.
- A listing longer than 1 MiB counts as no answer, instead of growing without bound.
- The kill test checks the process with kill -0, which works on every Unix.
- docs/printing.md: the only-printer fallback is on the lp and IPP routes, and the
  portal is Linux only.
2026-10-29 18:51:10 -04:00
FredApps c93c0bb36d Merge main into trimmed integration; reconcile blur, pattern and Liquify behavior 2026-10-29 23:47:53 +01:00
FredApps 29bf828ec2 Merge upstream main into reviewed performance integration
Preserve both UI parity status entries; retain all reviewed performance changes.
2026-10-29 23:35:19 +01:00
FredApps 73502a6b89 Reconcile Arrange no-op regression with retained command contract 2026-10-29 22:28:41 +01:00
FredApps 63637c4d80 Merge current main into trimmed integration, preserving exclusions and interpolation behavior 2026-10-29 21:31:18 +01:00
FredApps 255ecc81d0 Remove 21 requested PR contributions from the 108-PR integration
Retain 87 PRs. Reconcile overlapping integration fixes and update testing scope.
Removed: #7153 #7742 #5493 #9282 #3455 #9172 #3139 #3967 #4783 #5453 #8347 #1991 #3345 #4042 #4305 #4883 #4890 #5090 #6621 #5870 #5939.

Combined CI pending for this source; historical portable artifact is not applicable.
2026-10-29 18:49:17 +01:00
Federico Olivares 796ef557cc Merge main into the integration batch
Main's noop_step now takes the step's params (an Arrange that cannot move the layer is a no-op too); it is public for the CLI's run and batch, which pass them.
2026-10-29 14:19:54 -03:00
aiongg 2231233af9 Merge pull request #6590 from wanikhawar/fix/6501-multi-layer-free-transform
Free Transform moves every selected layer (#6501, #3384, #6096)
2026-10-29 12:14:01 -04:00
aiongg 3bcff338c5 Merge pull request #6421 from wanikhawar/save-for-web-webp
Save for Web: WebP, lossy at its Quality or lossless (part of #6391, #2415)
2026-10-29 12:12:47 -04:00
Khawar Zamman Wani 82096cff3a perf(retouch): avoid duplicate rasterization while drawing (#9532)
* perf(retouch): generate live dabs without unused coverage

* fix(ui): box live stroke variants after retouch state reduction
2026-10-29 12:12:33 -04:00
Khawar Zamman Wani 991ef9907b fix(actions): allow no-op Arrange steps during playback (#8457) 2026-10-29 11:34:13 -04:00
FredApps 53dbfe280c Integrate 16 reviewed performance and usability PRs
Includes #8472 #8488 #9461 #9793 #9809 #9813 #9814 #9822 #9826 #9847 #9850 #9852 #9921 #9924 #9961 #10080 at reviewed heads.

Preserves each PR head as a parent. Reconciles CI workflow inputs and benchmark jobs without dropping checks. Excludes #8536 #9825 #9969 #10129. Combined CI pending; no manual validation claimed.
2026-10-29 14:31:15 +01:00
FredApps e40cdadb63 Preserve opening snapshot assertions and refresh generated scorecard 2026-10-29 07:52:28 +01:00
FredApps 964a47b51c Reconcile history, gradient, type safety and UI validation behavior 2026-10-29 07:30:56 +01:00
Khawar Zamman Wani e2cd2a335a Composite smart object sources in tile-aligned blocks
Row strips of a very wide source still allocated whole 256-row tiles
across the full width for every few rows (about 293 MiB per strip of a
300000 px RGBA8 source). Blocks are now whole tiles, at most 4096 px wide
and 1 Mpx in all, and their tiles move into the result without a copy.
2026-10-29 11:48:58 +05:30
FredApps 11fdb18070 Fix integration validation regressions and enable manual full sweeps 2026-10-29 07:10:41 +01:00
FredApps 5a5e2c48dd Merge approved PhotoCraft PR #3345: Add grouped gradient presets and selectable style icons
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Port grouped gradient browsers and style previews into current modular sidebar/options controls. Keep current transactional stop preview, drag/drop ownership and sidebar activation semantics; add compact Properties preset picker without replacing stop engine. Preserve accessibility Role metadata and all approved regressions.
2026-10-29 06:37:29 +01:00
FredApps 4f23f459ba Merge approved PhotoCraft PR #3464: fix(vector): target selected saved paths and own Pen gestures
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Reconcile captured Pen and Freeform targets with current resumed-subpath, Type Path, Path Operation and draft recovery behavior. Valid source-owned tab switches commit to captured original target; invalid snapshots cancel with a diagnostic; refused commits retain draft and suppress automatic retries. Preserve current Saved(index) API and hidden-work-path protections, register all new ownership/gesture tests and add original-target tab-switch/deleted-target cases. Includes verified compile/API corrections from prior checkpoints.
2026-10-29 06:33:02 +01:00
Khawar Zamman Wani dafbff2b05 Test the web build's Memory Usage cap
The cap is now a function of the stored value and the target, so native
tests check values below, at and above it; the native-only assertions are
gated to native targets.
2026-10-29 11:02:50 +05:30
Khawar Zamman Wani 0eaf976088 Keep smart object source strips within their pixel budget
Rounding the strip height up to the compositor's 256-row tile let a very
wide source (300000 px) composite 76.8 Mpx in one strip. Strips are now as
many rows as fit in the budget, at least one; the equivalence test also
covers strips off the tile grid.
2026-10-29 11:02:50 +05:30
FredApps de48193ece Merge approved PhotoCraft PR #3519: feat(export): optionally trim transparent margins from layer files
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Port transparent-margin trim into current authorized streaming export report, retaining skipped-layer reasons and stable numbering. Measure alpha in bounded render bands, including masks/effects; keep empty-layer canvas and source document immutable. Preserve original regressions.
2026-10-29 06:15:09 +01:00
FredApps c9430c92e3 Merge approved PhotoCraft PR #3748: control: suggest near matches for unknown command ids and methods (#3674)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Add bounded deterministic suggestions via current error/session/control modules while preserving authorization/modal checks. Register hints and all original tests; fix scrollbar choice import and updated PSD image fixture field found by 100-head check.
2026-10-29 06:14:31 +01:00
FredApps dd428d2780 Merge approved PhotoCraft PR #4035: fix(cmyk): Flatten Image and merges keep the inks of a tagged CMYK document (#3778)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Current compositor already preserves plain CMYK inks, tagged profile separation and uncropped merge bounds. Keep stronger native CMYK/Lab paths and current merge API; apply profile context to style rasterization and retain approved tagged-CMYK regression fixtures.
2026-10-29 06:12:35 +01:00
FredApps 1daf3bc079 Merge approved PhotoCraft PR #4890: Add scrollbar visibility preferences (#3262)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Port visibility preference, choice registration, live panel style and canvas override. Keep current animated camera and toolbar exclusions. Relocate misplaced persistence regression to prefs tests; retain current parity score counts.
2026-10-29 06:09:52 +01:00
FredApps 32f583f1d6 Merge approved PhotoCraft PR #5082: fix(mixer-brush): Alt-click samples the foreground colour like the Brush (#4873)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Preserve current spatial Mixer Brush Alt-click sampling and live transaction architecture; add compatible point-sample command without foreground mutation. Retain sample across automatic reload until foreground changes and preserve all new regressions.
2026-10-29 06:05:02 +01:00
FredApps 1953077164 Merge approved PhotoCraft PR #5270: Layer Style: Gradient Overlay takes any number of colour stops (#5177)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Port arbitrary-stop editor into current responsive dialog. Preserve source interpolation and exact model colors; unchanged dense imported snapshot lists roundtrip while edited lists retain 256-stop cap. Retain both validation guards and all original regression tests. Correct saved-path callers, floating-window and crop fixtures found by frozen 88-head all-target check.
2026-10-29 06:02:29 +01:00
FredApps 8323688e1f Merge approved PhotoCraft PR #5453: Shapes: independent fill and stroke paints (solid, gradient, pattern), part 1
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Integrated independent exact shape paints and atomic pattern clipboard snapshots into current modules, preserving current soft-mask coverage, shape cache keys and gradient stop caps. Shared bounded COW pattern sampling now retains minification filtering; shapes/clipboards resolve lazy catalog entries to full pixels. Preserved CPU/GPU/depth/model regression matrices; also corrected missing glow-test enum imports found by the 80-head check.
2026-10-29 05:53:29 +01:00
FredApps c81347aaa8 Merge approved PhotoCraft PR #5493: Import Photoshop custom shape sets into the Shapes panel
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Integrated bounded atomic CSH set parsing, unique shape/group naming and native Shapes panel import with inline-data authorization guards; preserved duplicate-name, inner-hole, malformed-second-record and preferences-reload regressions. Combined independent catalog additions and retained current parity metadata.
2026-10-29 05:47:45 +01:00
FredApps 9df3697de8 Merge approved PhotoCraft PR #5650: Guides: ⌥ turns a dragged guide; dropping one on either ruler deletes it (#5034)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Added Alt guide rotation in current ruler/tool-input modules and engine Move Guide, retaining click-versus-drag selection, deletion on either ruler, colors, ruler-origin units and snapping. Selection follows the new orientation/index after a successful turn; original guide-turn/deletion regressions retained.
2026-10-29 05:46:02 +01:00
FredApps a72296ee57 Merge approved PhotoCraft PR #6139: Fix painting workflows, File Info and layer selection
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Ported Behind paint across engine/render and shared options-bar/canvas mode menus, preserving Clear and current popup ownership. Added localized responsive picker title/width and File Info multiline fields without dropping ordered fields, Browse or camera metadata; ported Pen anchor repositioning, copy cursor, grayscale-target sampling and authorized select-under-cursor dispatch into current modules with original regressions.
2026-10-29 05:39:00 +01:00
Khawar Zamman Wani a4cb9cd729 Test smart object source compositing across strip edges
The equivalence tests used a 64x48 source, a single strip, so a shadow or
mask crossing a strip boundary was never compared with the full-size path.
2026-10-29 10:08:06 +05:30
Khawar Zamman Wani 10f0648058 Cap the history budget on the web build
The default Memory Usage is 8 GiB per document, above the 4 GiB a
wasm module can address, so on the web the History budget could never
be reached and trimming never ran.

Performance::effective_memory_usage_mb caps the stored preference at
1536 MB on wasm32 and returns it unchanged elsewhere. The History
budget, the transform budget and the canvas allowance in the UI read
it. The stored preference and its default are untouched, so a saved
8192 still loads and still means 8192 on desktop.
2026-10-29 10:03:25 +05:30
Khawar Zamman Wani b779bd8f02 Count embedded smart object contents toward the history budget
History counted a document's pixel tiles but not the file bytes a
smart object embeds (SmartSource::Embedded). A document of large
embedded sources was far over its memory budget without trimming
ever noticing, and every Replace Contents kept the old bytes alive in
the undo states unaccounted.

The four counters (add, remove, bytes_with and the uncounted walk)
now visit one shared list of blocks: the tiles as before plus each
embedded source's Arc, keyed by address. States, snapshots and
duplicated layers that share an Arc count it once, and trimming the
last state that holds an old source releases it.
2026-10-29 10:03:25 +05:30
Khawar Zamman Wani e96386fe47 Bound and purge the decoded smart object source cache
The cache estimated an entry at channels * 4 bytes a pixel, four times
too much for 8-bit, always kept a single oversize entry, recovered a
poisoned lock by disabling itself, and nothing ever cleared it.

Count each entry's real tile bytes once when it is cached, and do not
cache a source larger than the whole budget (as the stage cache does).
Web builds keep 4 entries and 384 MiB instead of 32 and 1 GiB, and the
smart filter stage cache 256 MiB instead of 768 MiB. A poisoned lock
is recovered rather than ignored.

Edit > Purge > All now clears the cache and reports it, and enables on
it alone. Closing a document that has smart objects clears it too:
entries are shared by content hash, so other documents just decode
again on their next re-render.
2026-10-29 10:03:25 +05:30
Khawar Zamman Wani ee57fdb90e Smart object sources decode through the strip compositor
The first re-render of a smart object (Free Transform commit, Image
Size, a filter edit) flattened its source into one full-size RGBA
float buffer (16 bytes a pixel) and then converted it into a second
f32 vector before the surface was built, about 32 bytes a pixel on top
of the decoded document.

Composite the source in strips of about a megapixel straight into the
target pixel format instead. RGB, Grayscale and the depth conversions
give the same pixels as before (checked bit for bit, including masks,
blend modes and layer effects). CMYK and Lab composite natively in the
banded compositor and land up to 16 and 1 steps (8-bit) off the buffer
path, so sources in those modes keep the buffer path.

A 4096x4096 RGBA8 source now peaks +191 MiB (12.0 B/px) instead of
+655 MiB (41.0 B/px); tests/smart_source_peak.rs holds it under 16 B/px.
2026-10-29 10:03:25 +05:30
FredApps a62b9ee217 Merge approved PhotoCraft PR #8347: Type: Roman Hanging Punctuation (trailing marks hang, don't steer the alignment)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Ported hanging punctuation into current line placement and kerning modules, preserving forced breaks, bounded edge-tip row merging, justified-last-line behavior, area exclusions and independent Roman orientation shaping; kept PSD/engine/UI regression coverage.
2026-10-29 05:22:57 +01:00
FredApps 2e2eec3a43 Merge approved PhotoCraft PR #9478: fix(text): vertical type sets roman letters upright, one per em, as Photoshop does (#9470)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Ported upright Roman classification, independent unkerned/unligated em advances and tab reflow into current Para/VerticalPiece shaping modules; preserved area and paragraph flow; retained vertical geometry and PSD BaselineDirection regressions.
2026-10-29 05:18:29 +01:00
FredApps d98e419542 Merge approved PhotoCraft PR #5176: Play CopyCat, AJ and Line and Color action sets; keep patterns across restarts; Shift Edge scale
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Ported mappings and smart Save into current modules, preserving bounded authorized playback; migrated legacy PAT by committing validated per-pattern assets before atomic authoritative index; preserved same-ID replacements and builtin edits; added temporary-store interruption, corruption, duplicate ID/name and restart regression coverage. Current all-target compilation passed before final ownership guard refinement; focused tests pending.
2026-10-29 05:15:28 +01:00
FredApps 889018cabb Preserve action definition history regression with extended action metadata 2026-10-29 05:05:06 +01:00
FredApps e0bca6baf6 Use explicit float mask format in combined Fill parity regression 2026-10-29 05:02:27 +01:00
FredApps 7da5d15a34 Merge approved PhotoCraft PR #7255: fix(engine): guard trim and duplicate merged against documents exceeding render limits (#7223)
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Preflight existing render-cap helper before allocation, retain post-render completeness checks, and preserve the oversized Trim/Duplicate atomic-refusal regression.
2026-10-29 04:53:33 +01:00