如何在Camera2中修改预览及拍摄的宽高比?现有尝试未生效
Camera2 修改宽高比的正确实现方法
要在Camera2里修改拍摄/预览的宽高比,核心是必须使用相机硬件支持的分辨率参数,不能随意自定义尺寸,否则要么被系统强制 fallback 到默认宽高比,要么出现画面变形。以下是具体步骤:
1. 先获取相机支持的对应宽高比的分辨率
相机硬件只支持固定的分辨率组合,你需要先从相机特性中筛选出目标宽高比的可用尺寸:
// 获取CameraCharacteristics CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); // 获取流配置映射 StreamConfigurationMap configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); // 筛选目标宽高比(比如1:1)的JPEG输出尺寸(用于拍照) int targetAspectRatioNumerator = 1; int targetAspectRatioDenominator = 1; Size[] jpegSizes = configMap.getOutputSizes(ImageFormat.JPEG); Size selectedJpegSize = null; for (Size size : jpegSizes) { int width = size.getWidth(); int height = size.getHeight(); // 计算宽高比的最简形式,避免因尺寸不同导致判断错误 int gcd = gcd(width, height); int ratioW = width / gcd; int ratioH = height / gcd; if (ratioW == targetAspectRatioNumerator && ratioH == targetAspectRatioDenominator) { selectedJpegSize = size; break; // 也可选择最合适的分辨率,比如最大的1:1尺寸 } } // 同理筛选预览用的SurfaceTexture支持的尺寸(比如1:1) Size[] previewSizes = configMap.getOutputSizes(SurfaceTexture.class); Size selectedPreviewSize = null; for (Size size : previewSizes) { int gcd = gcd(size.getWidth(), size.getHeight()); int ratioW = size.getWidth() / gcd; int ratioH = size.getHeight() / gcd; if (ratioW == targetAspectRatioNumerator && ratioH == targetAspectRatioDenominator) { selectedPreviewSize = size; break; } } // 辅助计算最大公约数的方法 private int gcd(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; }
2. 正确配置ImageReader(拍照用)
使用上面筛选出的selectedJpegSize来创建ImageReader,而不是自定义500x500:
ImageReader imageReader = ImageReader.newInstance( selectedJpegSize.getWidth(), selectedJpegSize.getHeight(), ImageFormat.JPEG, 1 );
3. 避免预览画面变形
- 第一步:用筛选出的
selectedPreviewSize设置SurfaceTexture的默认缓冲尺寸:
surfaceTexture.setDefaultBufferSize( selectedPreviewSize.getWidth(), selectedPreviewSize.getHeight() );
- 第二步:确保预览控件(TextureView/SurfaceView)的布局宽高比和
selectedPreviewSize的宽高比一致。比如在布局文件中设置android:layout_width="match_parent",android:layout_height="0dp",然后用app:layout_constraintDimensionRatio="1:1"来强制1:1比例;或者在代码中动态计算控件的高度,保持宽高比。
4. 配置CaptureRequest时的注意事项
- 拍照的CaptureRequest需要将ImageReader的Surface加入输出目标:
CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(imageReader.getSurface()); // 其他参数设置(自动对焦、曝光等)
- 如果需要对画面进行裁剪(比如相机原生没有目标宽高比的分辨率),可以通过设置
CaptureRequest.SCALER_CROP_REGION来实现,但这会损失部分画面内容:
// 计算裁剪区域,以1:1为例 Rect sensorRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); int cropWidth = Math.min(sensorRect.width(), sensorRect.height()); int cropLeft = (sensorRect.width() - cropWidth) / 2; int cropTop = (sensorRect.height() - cropWidth) / 2; Rect cropRegion = new Rect(cropLeft, cropTop, cropLeft + cropWidth, cropTop + cropWidth); captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegion);
内容的提问来源于stack exchange,提问作者user20468245
相关产品推荐
相关产品推荐

