fix(4x3): force frame stream to 4:3 sensor aspect via targetResolution
This commit is contained in:
@@ -155,6 +155,35 @@ export default function Viewfinder({
|
||||
// enough to pick the device up — no manual polling needed.
|
||||
const device = useCameraDevice('back');
|
||||
|
||||
// CameraX negotiates the CameraFrameOutput aspect on its own (default 16:9 on
|
||||
// this device), which center-crops the 4:3 sensor — so the ratio band could
|
||||
// never display 100% of the sensor pixels. Force the frame stream to a 4:3
|
||||
// (sensor aspect) resolution supported for 'stream' outputs; the photo output
|
||||
// keeps its own full-res 4:3 size and FOV, so the viewfinder then matches the
|
||||
// captured photo exactly. Best supported 4:3 size closest to 1280x960
|
||||
// (720p-class, keeps the frame pipeline light); CameraX may still round it.
|
||||
const frameTarget = useMemo(() => {
|
||||
if (!device) return undefined;
|
||||
try {
|
||||
let best: { width: number; height: number } | undefined;
|
||||
let bestScore = Infinity;
|
||||
for (const s of device.getSupportedResolutions('stream')) {
|
||||
const w = s.width;
|
||||
const h = s.height;
|
||||
if (!(w > 0 && h > 0)) continue;
|
||||
if (Math.abs(w / h - 4 / 3) > 0.03) continue;
|
||||
const score = Math.abs(Math.sqrt(w * h) - Math.sqrt(1280 * 960));
|
||||
if (score < bestScore) {
|
||||
bestScore = score;
|
||||
best = { width: w, height: h };
|
||||
}
|
||||
}
|
||||
return best ?? undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}, [device]);
|
||||
|
||||
const skiaImage = useImage(libraryImageUri || '');
|
||||
// Wall-frame PNG artwork (project root). Loaded lazily so other frames pay
|
||||
// no asset cost; source switches to '' when unselected (useImage → null).
|
||||
@@ -629,7 +658,8 @@ export default function Viewfinder({
|
||||
' ratio=' + aspectRatio +
|
||||
' frame=' + selectedFrame +
|
||||
' view=' + vw + 'x' + vh +
|
||||
' feed=' + (cameraPhotoRect ? JSON.stringify([1, vw / vh, cameraPhotoRect.x / vw, cameraPhotoRect.y / vh, cameraPhotoRect.w / vw, cameraPhotoRect.h / vh]) : 'null')
|
||||
' feed=' + (cameraPhotoRect ? JSON.stringify([1, vw / vh, cameraPhotoRect.x / vw, cameraPhotoRect.y / vh, cameraPhotoRect.w / vw, cameraPhotoRect.h / vh]) : 'null') +
|
||||
' frameTarget=' + (frameTarget ? frameTarget.width + 'x' + frameTarget.height : 'null')
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [region, regionBand, aspectRatio, selectedFrame, cameraPhotoRect]);
|
||||
@@ -956,6 +986,7 @@ export default function Viewfinder({
|
||||
isActive={appActive}
|
||||
outputs={cameraOutputs}
|
||||
pixelFormat="yuv"
|
||||
targetResolution={frameTarget}
|
||||
onStarted={() => setCameraActive(true)}
|
||||
onFrame={handleFrame}
|
||||
onError={onSessionError}
|
||||
|
||||
Reference in New Issue
Block a user