mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-28 03:47:00 -06:00
* fix(compose): a wide stroke effect keeps a round outer edge (#3646) A stroke's outside distance came from the 5x5 chamfer, whose level sets are polygons: at a 245 px outside stroke the boundary wanders ~10 px into visible flat facets. Use the exact Euclidean distance (edt_nearest, already used for glows and chiselled bevels) for the outer edge; the inside edge and spread/choke keep the chamfer, whose sub-pixel edge seeding is fitted to Photoshop at small offsets. A point source dilated by 60 px now stays within 0.5 px of a circle (was 2.5 px). Tests: a_wide_outside_stroke_is_round_not_a_polygon; stroke_edges_use_the_exact_euclidean_distance (a 3 px outside stroke's (1,3) corner coverage is 0.838, the exact distance; it was 0.764). Full photocraft-compose suite: 206 pass; fmt and clippy clean. * fix(gpu): a wide stroke keeps its exact outer edge on the GPU (#3646) 1080008a fixed the CPU compositor's stroke outer edge to use the exact Euclidean distance instead of the 5x5 chamfer, whose level sets are polygons and facet a wide stroke. The GPU compositor builds the outer stroke field from FieldKind::StrokeOutside, which still maps to the chamfer, and the canvas is drawn on the GPU, so the fix did not reach the app. Add FieldKind::StrokeOutsideExact (dist_outside_by Euclidean) used only by the stroke. The spread of drop shadows and softer outer glows keeps the chamfer on purpose (fitted to Photoshop, #224), so StrokeOutside keeps its meaning. StrokeOutsideVector is exact too, matching the CPU vector outline path. Tests: crates/gpu/src/fx.rs a_raster_stroke_uses_the_exact_outer_field (stroke uses the exact field, shadow spread keeps the chamfer), and the banded/whole field test covers the new kind. * fix(stroke): a stroke keeps the chamfer narrow and the exact edge wide (#3646) The exact Euclidean outer edge (#3646) fixed a wide stroke's faceting but regressed Photoshop's own composites against the PSD flatten oracle: the fitted 5 × 5 chamfer matches Photoshop at small offsets, and only at a large outside width do its octagon facets show. Pick the metric by the stroke's outside width instead: below `STROKE_CHAMFER_MAX` (20 px) keep the chamfer and its sub-pixel edge seeding, at or above it use the exact Euclidean transform. The measured chamfer deviation from a point source is 0.027 · r px — 0.48 px at r = 18, the widest outside stroke any Photoshop oracle matches with the chamfer, and 1.6 px at r = 60, where the boundary visibly facets. Half a pixel is reached at r ≈ 19, so the switch sits at 20. Inside stroke edges keep the chamfer. The CPU and GPU compositors pick the same field by the same width (`stroke_outside_exact`); `FieldKind` gains `StrokeOutsideVectorChamfer` for a narrow shape-layer outline, while the shadow / glow spread keeps its chamfer. io corpus: 140 → 148 (floor 146) and psd-tools 231 → 237 (floor 236), both back to main's counts with no file newly differing; a 60 px outside stroke stays round (`a_wide_outside_stroke_is_round_not_a_polygon`).