我已经创建了一个库(请查看this以获取更多信息),因为Android for Android Camera2功能在Android中运行良好,但是在全屏相机的宽高比问题上。
请检查下面的图像,它在预览和真实图片中的外观(只有预览的问题不是拍摄后的真实照片)
捕获的图像水平:
水平预览图片:
垂直捕获的图像:
垂直预览图片:
Google的Camera2 API样本有类似的问题并已解决here。
但是同样的代码在我的本机库代码中没有工作。可能是我正在使用一个代码用于图像和视频,并添加额外的视频捕获代码。
答案 0 :(得分:1)
通常,相机传感器的宽高比与屏幕宽高比不匹配。结果就是您目前正在经历的事情。
由于纵横比不匹配。您实际上无法强制预览为全屏。您有选择“有效”尺寸。那你怎么做的?
我们无法对传感器的尺寸做些什么。我们要回答的问题是我的预览高度应该是多少? (假设肖像模式)
以下是一个例子:
传感器(假设人像):
屏幕(假设肖像):
使用上述值,您的预览图像将“伸展”。
以下是修复方法:
我们知道我们想要的宽高比: 0.5
宽度/高度= 0.5
我们知道屏幕的宽度(纵向): 400
400 /身高= 0.5
身高= 400 / 0.5 = 800
为了不在x或y方向拉伸,高度(假设为肖像)需要为:预览宽度/所需宽高比
答案 1 :(得分:0)
我为想要更多理论的任何人详细回答了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。