以下答案假设您仅处于纵向模式。
你的问题是
如何在不拉伸的情况下全屏使用预览
让我们把它分解成两件事:
- 您希望预览充满整个屏幕
- 预览不能失真
首先,您需要知道如果您的设备的视口具有不同的纵横比以及相机提供的任何可用分辨率,这在逻辑上是不可能的没有裁剪。
所以我假设你接受裁剪预览。
第 1 步:获取可用分辨率列表
StreamConfigurationMap map = mCameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
throw new IllegalStateException("Failed to get configuration map: " + mCameraId);
}
Size[] sizes = map.getOutputSizes(SurfaceTexture.class);
现在您将获得设备相机的可用分辨率(尺寸)列表。
第 2 步:找到最佳纵横比
我们的想法是循环尺寸并查看最适合的尺寸。您可能需要编写自己的“最佳匹配”实现。
我不会在这里提供任何代码,因为我所拥有的与您的用例完全不同。但理想情况下,它应该是这样的:
Size findBestSize (Size[] sizes) {
//Logic goes here
}
第 3 步:告诉 Camera API 您要使用此尺寸
//...
textureView.setBufferSize(bestSize.getWidth(), bestSize.getHeight());
Surface surface = textureView.getSurface();
try {
mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
mSessionCallback, null);
} catch (final Exception e) {
//...
}
第 4 步:让预览超出视口范围
这与 Camera2 API 无关。我们通过让SurfaceView / TextureView 超出设备的视口来“裁剪”预览。
首先将您的SurfaceView 或TextureView 放入RelativeLayout。
在您从第 2 步获得纵横比后,使用以下内容将其扩展到屏幕之外。
请注意,在这种情况下,您可能需要在启动相机之前知道此纵横比。
//Suppose this value is obtained from Step 2.
//I simply test here by hardcoding a 3:4 aspect ratio, where my phone has a thinner aspect ratio.
float cameraAspectRatio = (float) 0.75;
//Preparation
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
int finalWidth = screenWidth;
int finalHeight = screenHeight;
int widthDifference = 0;
int heightDifference = 0;
float screenAspectRatio = (float) screenWidth / screenHeight;
//Determines whether we crop width or crop height
if (screenAspectRatio > cameraAspectRatio) { //Keep width crop height
finalHeight = (int) (screenWidth / cameraAspectRatio);
heightDifference = finalHeight - screenHeight;
} else { //Keep height crop width
finalWidth = (int) (screenHeight * cameraAspectRatio);
widthDifference = finalWidth - screenWidth;
}
//Apply the result to the Preview
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) cameraView.getLayoutParams();
lp.width = finalWidth;
lp.height = finalHeight;
//Below 2 lines are to center the preview, since cropping default occurs at the right and bottom
lp.leftMargin = - (widthDifference / 2);
lp.topMargin = - (heightDifference / 2);
cameraView.setLayoutParams(lp);
如果您不关心第 2 步的结果,您实际上可以忽略第 1 步到第 3 步,只需使用那里的库,只要您可以配置其纵横比即可。 (貌似this one是最好的,但我还没试过)
我已经使用my forked library 进行了测试。在不修改我的库的任何代码的情况下,我仅使用第 4 步就设法使预览全屏:
在使用第 4 步之前:
使用第4步后:
拍照后的预览也不会失真,因为预览也超出了您的屏幕。
但是输出的图像会包含您在预览中看不到的区域,这使得完美的感觉。
步骤1到步骤3的代码一般引用自Google's CameraView。