diff --git a/src/components/Viewfinder.tsx b/src/components/Viewfinder.tsx index 8b5cf81..882bc68 100644 --- a/src/components/Viewfinder.tsx +++ b/src/components/Viewfinder.tsx @@ -126,13 +126,21 @@ export default function Viewfinder({ (selectedFrame === 'none' || selectedFrame === 'classic-white' || selectedFrame === 'cinematic'); const region = useMemo(() => { if (!regionBand || ratioWH === null) return { x: 0, y: 0, w: vw, h: vh }; - const h = vw / ratioWH; - if (h <= vh) { - return { x: 0, y: (vh - h) / 2, w: vw, h }; - } - // Screen narrower than the ratio: fit by height, letterbox the sides. - const w = vh * ratioWH; - return { x: (vw - w) / 2, y: 0, w, h }; + // The band is a same-zoom crop WINDOW over the full sensor view, not the + // photo re-scaled to the screen width: anchor on the native sensor box + // (upright 3:4, contain-fitted to the screen) and cut the ratio strip out + // of it at the same scale. 4:3 (== native) therefore fills the full sensor + // width at the reference zoom, and 3:2 is the identical vertical view with + // a narrower horizontal crop — switching ratio never zooms the scene, so a + // 3:2 band never shows a taller image than 4:3. + // ponytail: sensor assumed upright 3:4 (quality-mode captures); if a device + // negotiates another photo aspect, derive it from the session instead. + const nativeWH = 3 / 4; + const nativeH = Math.min(vh, vw / nativeWH); + const nativeW = nativeH * nativeWH; + const h = ratioWH <= nativeWH ? nativeH : nativeW / ratioWH; + const w = ratioWH * h; + return { x: (vw - w) / 2, y: (vh - h) / 2, w, h }; }, [regionBand, ratioWH, vw, vh]); // Camera outputs: attach the DNG output only while RAW is on — CameraX // cannot bind two ImageCapture use cases at once, and App's session-error