From 1d96269139d03ef0a2a55ee1a04616a9849083f8 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Tue, 22 Sep 2026 10:45:07 +0700 Subject: [PATCH] web: keep compare on offer, and compare at the cropped size Choosing a crop ratio used to disable COMPARE outright, because the split painted the whole original into a box that was now the crop's shape. The original is now looked at through a window of the render's own shape: with a crop applied the photo is scaled and slid by the crop rect so the same rectangle lines up, and the split compares like with like. The window needs the image free to overflow it, so the inline style lifts the box clamp that .canvas-wrap img puts on every preview. --- docker/frontend/src/App.tsx | 3 +- docker/frontend/src/styles/app.css | 3 ++ docker/frontend/src/ui/ImageStage.tsx | 51 +++++++++++++++++++++------ 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/docker/frontend/src/App.tsx b/docker/frontend/src/App.tsx index 946c0f5..3166d60 100644 --- a/docker/frontend/src/App.tsx +++ b/docker/frontend/src/App.tsx @@ -2472,7 +2472,8 @@ export function Workspace() { cropWH={cropWH} onCropRectChange={setCropRect} onStageZoom={onStageZoom} - canCompare={crop === 'none'} + canCompare={!!source} + compareCrop={cropLive ? cropRect : null} onSaveOriginal={() => void saveOriginal()} onClear={() => setClearing(true)} picking={picking} diff --git a/docker/frontend/src/styles/app.css b/docker/frontend/src/styles/app.css index 1661be2..cc1559b 100644 --- a/docker/frontend/src/styles/app.css +++ b/docker/frontend/src/styles/app.css @@ -284,6 +284,9 @@ input[type="range"] { width: 100%; accent-color: var(--accent); } cursor: ew-resize; touch-action: none; } +/* The window the original is looked at through: the render's own shape, so a + crop can slide and scale the photo behind it and still line up. */ +.compare-window { position: absolute; inset: 0; overflow: hidden; } .compare-orig { position: absolute; inset: 0; width: 100%; height: 100%; box-shadow: none; } .compare-bar { position: absolute; diff --git a/docker/frontend/src/ui/ImageStage.tsx b/docker/frontend/src/ui/ImageStage.tsx index 1cc0f3b..0b97535 100644 --- a/docker/frontend/src/ui/ImageStage.tsx +++ b/docker/frontend/src/ui/ImageStage.tsx @@ -65,6 +65,9 @@ export function ImageStage({ onCropRectChange, onStageZoom, canCompare = false, + // The crop the render is already carrying: the original is shown through the + // same window, so the two halves line up whatever the shape. + compareCrop = null, onSaveOriginal, // Takes the photo off the stage. What is on it goes first — the confirmation // offers to file the frame or export it, so nothing is lost by accident. @@ -93,9 +96,11 @@ export function ImageStage({ // at — the app re-cuts its preview copy to match. Scaled to contain the // photo and multiplied by the zoom and the screen's pixel ratio. onStageZoom?: (longDevicePx: number) => void; - // Compare needs the un-cropped photo on one side and the render on the other, - // so it is only offered while the crop is untouched. + // Compare puts the photo that was loaded beside the render, and the crop is + // part of that render: when one is applied the original is shown through the + // same window, so the split stays a straight line-up. canCompare?: boolean; + compareCrop?: CropRect | null; // Puts the untouched photo file itself in the owner's hands — on a phone that // is the share sheet, whose "Save Image" is what reaches the photo library. onSaveOriginal?: () => void; @@ -757,7 +762,7 @@ export function ImageStage({ {straightenRuler} ) : null} - {compare && canCompare && originalUrl && box ? ( + {compare && canCompare && !cropEditing && originalUrl && box ? (
{/* The original is clipped to everything left of the bar; the - graded render stays the un-clipped base underneath it. */} - + > + +