发布于 2017-12-06 23:10:02
通常情况下,相机传感器的纵横比与屏幕的纵横比不匹配。结果就是你目前正在经历的事情。
由于宽高比的这种不匹配。你不能强制预览是全屏的。你必须选择“有效”尺寸。那么如何做到这一点呢?
我们对传感器的尺寸无能为力。我们必须回答的问题是,我的预览的高度应该是多少?(假设为纵向模式)
下面是一个例子:
传感器(假设为纵向):
屏幕(假设为纵向):
有了上面的值,你的预览图像将被“拉伸”。
下面是如何修复它:
我们知道我们想要的纵横比:0.5
宽度/高度= 0.5
我们知道屏幕的宽度(纵向):400
400 /高度= 0.5
高度= 400 / 0.5 = 800
为了在x或y方向上没有拉伸,高度(假设为纵向)需要为:预览宽度/所需的纵横比
发布于 2020-08-06 19:17:15
我为那些想要更多理论的人详细回答了一个similar question here。
简而言之,在cameraReady上,你必须抓取屏幕尺寸,支持的摄像头宽高比,然后找到与屏幕最匹配的比例,而不是太高。
示例应用程序如下所示:
import React, { useEffect, useState } from 'react';
import {StyleSheet, View, Text, Dimensions, Platform } from 'react-native';
import { Camera } from 'expo-camera';
import * as Permissions from 'expo-permissions';
export default function App() {
// camera permissions
const [hasCameraPermission, setHasCameraPermission] = useState(null);
const [camera, setCamera] = useState(null);
// Screen Ratio and image padding
const [imagePadding, setImagePadding] = useState(0);
const [ratio, setRatio] = useState('4:3'); // default is 4:3
const { height, width } = Dimensions.get('window');
const screenRatio = height / width;
const [isRatioSet, setIsRatioSet] = useState(false);
// on screen load, ask for permission to use the camera
useEffect(() => {
async function getCameraStatus() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
setHasCameraPermission(status == 'granted');
}
getCameraStatus();
}, []);
// set the camera ratio and padding.
// this code assumes a portrait mode screen
const prepareRatio = async () => {
let desiredRatio = '4:3'; // Start with the system default
// This issue only affects Android
if (Platform.OS === 'android') {
const ratios = await camera.getSupportedRatiosAsync();
// Calculate the width/height of each of the supported camera ratios
// These width/height are measured in landscape mode
// find the ratio that is closest to the screen ratio without going over
let distances = {};
let realRatios = {};
let minDistance = null;
for (const ratio of ratios) {
const parts = ratio.split(':');
const realRatio = parseInt(parts[0]) / parseInt(parts[1]);
realRatios[ratio] = realRatio;
// ratio can't be taller than screen, so we don't want an abs()
const distance = screenRatio - realRatio;
distances[ratio] = realRatio;
if (minDistance == null) {
minDistance = ratio;
} else {
if (distance >= 0 && distance < distances[minDistance]) {
minDistance = ratio;
}
}
}
// set the best match
desiredRatio = minDistance;
// calculate the difference between the camera width and the screen height
const remainder = Math.floor(
(height - realRatios[desiredRatio] * width) / 2
);
// set the preview padding and preview ratio
setImagePadding(remainder / 2);
setRatio(desiredRatio);
// Set a flag so we don't do this
// calculation each time the screen refreshes
setIsRatioSet(true);
}
};
// the camera must be loaded in order to access the supported ratios
const setCameraReady = async() => {
if (!isRatioSet) {
await prepareRatio();
}
};
if (hasCameraPermission === null) {
return (
<View style={styles.information}>
<Text>Waiting for camera permissions</Text>
</View>
);
} else if (hasCameraPermission === false) {
return (
<View style={styles.information}>
<Text>No access to camera</Text>
</View>
);
} else {
return (
<View style={styles.container}>
{/*
We created a Camera height by adding margins to the top and bottom,
but we could set the width/height instead
since we know the screen dimensions
*/}
<Camera
style={[styles.cameraPreview, {marginTop: imagePadding, marginBottom: imagePadding}]}
onCameraReady={setCameraReady}
ratio={ratio}
ref={(ref) => {
setCamera(ref);
}}>
</Camera>
</View>
);
}
}
const styles = StyleSheet.create({
information: {
flex: 1,
justifyContent: 'center',
alignContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#000',
justifyContent: 'center',
},
cameraPreview: {
flex: 1,
}
});您也可以使用try this code out online or in your Android on Expo Snack。
https://stackoverflow.com/questions/47551921
复制相似问题