From 4000696bc7a5974f947988a83ccd1c1a375a591e Mon Sep 17 00:00:00 2001 From: stirling-image Date: Tue, 14 Apr 2026 15:49:42 +0800 Subject: [PATCH] fix(passport-photo): make preview WYSIWYG - remove zoom, what you see is what you download - Removed zoom controls entirely from preview pane - Canvas always shows exact passport photo output at 1:1 - Drag to adjust position still works for fine-tuning - Overlay lines use crop coordinates directly instead of zoom-adjusted ones - Added "what you see is what you download" label with output dimensions --- .../tools/passport-photo-settings.tsx | 86 ++++--------------- 1 file changed, 18 insertions(+), 68 deletions(-) diff --git a/apps/web/src/components/tools/passport-photo-settings.tsx b/apps/web/src/components/tools/passport-photo-settings.tsx index 6d57875f..864bf9ea 100644 --- a/apps/web/src/components/tools/passport-photo-settings.tsx +++ b/apps/web/src/components/tools/passport-photo-settings.tsx @@ -936,7 +936,7 @@ export function PassportPhotoPreview() { canvasDisplayHeight = Math.round(canvasDisplayWidth / aspectRatio); } - // Canvas stays the same size; zoom crops into a sub-region of the passport photo + // Canvas always shows exactly what will be downloaded - no zoom distortion canvas.width = canvasDisplayWidth; canvas.height = canvasDisplayHeight; @@ -951,18 +951,12 @@ export function PassportPhotoPreview() { const scaleX = img.naturalWidth / imageWidth; const scaleY = img.naturalHeight / imageHeight; - // When zoom > 1, show a sub-region centered on the face - const zoomedW = crop.photoWidthPx / zoom; - const zoomedH = crop.photoHeightPx / zoom; - const zoomedLeft = crop.leftX + (crop.photoWidthPx - zoomedW) / 2; - const zoomedTop = crop.topY + (crop.photoHeightPx - zoomedH) / 2; + const srcX = crop.leftX * scaleX; + const srcY = crop.topY * scaleY; + const srcW = crop.photoWidthPx * scaleX; + const srcH = crop.photoHeightPx * scaleY; - const srcX = zoomedLeft * scaleX; - const srcY = zoomedTop * scaleY; - const srcW = zoomedW * scaleX; - const srcH = zoomedH * scaleY; - - // Draw preview image onto full canvas + // Draw preview image onto full canvas - this is exactly what gets downloaded ctx.drawImage(img, srcX, srcY, srcW, srcH, 0, 0, canvasDisplayWidth, canvasDisplayHeight); // Compliance overlay @@ -973,9 +967,11 @@ export function PassportPhotoPreview() { ctx.setLineDash([6, 4]); ctx.lineWidth = 1.5; - // Helper: convert original-image coords to canvas coords (zoom-aware) - const toCanvasY = (origY: number) => ((origY - zoomedTop) / zoomedH) * canvasDisplayHeight; - const toCanvasX = (origX: number) => ((origX - zoomedLeft) / zoomedW) * canvasDisplayWidth; + // Helper: convert original-image coords to canvas coords + const toCanvasY = (origY: number) => + ((origY - crop.topY) / crop.photoHeightPx) * canvasDisplayHeight; + const toCanvasX = (origX: number) => + ((origX - crop.leftX) / crop.photoWidthPx) * canvasDisplayWidth; // Center line (vertical) - face centered check const centerXCanvas = toCanvasX((landmarks.faceCenterX + adjustX) * imageWidth); @@ -1059,15 +1055,6 @@ export function PassportPhotoPreview() { }; }, [dragging, setAdjustX, setAdjustY]); - // Wheel zoom - const handleWheel = useCallback( - (e: React.WheelEvent) => { - e.preventDefault(); - setZoom(Math.max(1, Math.min(3, zoom + (e.deltaY > 0 ? -0.1 : 0.1)))); - }, - [zoom, setZoom], - ); - // No file / no analysis state if (!analyzeResult && !analyzing) { return ( @@ -1102,59 +1089,22 @@ export function PassportPhotoPreview() { return (
- {/* Zoom controls */} -
- - - {Math.round(zoom * 100)}% - - - {zoom !== 1 && ( - - )} - - {pxDims.w}x{pxDims.h}px - + {/* Output dimensions */} +
+ Output: {pxDims.w}x{pxDims.h}px - what you see is what you download
- {/* Canvas */} + {/* Canvas - WYSIWYG preview */}
-
-
- - Drag to adjust -
-
- Scroll to zoom -
+
+ + Drag to adjust position