Android 14/15拍照后顶部出现黑条问题求助
安卓14/15拍照后图片顶部出现黑条问题解决思路
问题描述
在Android 14和15系统中,相机预览界面显示完整,但拍摄完成后图片顶部出现黑条。尝试调整ImageCapture的目标分辨率(如1280×720、4256×2832)后,问题仍未解决。
原代码示例
Preview preview = new Preview.Builder() .build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); ImageCapture imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) .setTargetResolution(new Size(1280, 720)) .setTargetRotation(Surface.ROTATION_0) .build(); mActivityCaptureImagesBinding.imbCapture.setOnClickListener(v -> { imageCapture.takePicture(Runnable::run, new ImageCapture.OnImageCapturedCallback() { @Override public void onCaptureSuccess(ImageProxy imageProxy) { bmpCaptured = mActivityCaptureImagesBinding.captureImageCameraPreview.getBitmap(); showHidePreviewScreen(); } @Override public void onError(ImageCaptureException exception) { Log.e(TAG_IMAGES_CAPTURE, "Exception while taking image : " + exception.getMessage()); } }); }); camera = cameraProvider.bindToLifecycle( (LifecycleOwner) this, cameraSelector, preview, imageCapture); } private void showHidePreviewScreen() { try { runOnUiThread(() -> { mActivityCaptureImagesBinding.imvPreview.setImageBitmap(bmpCaptured); mActivityCaptureImagesBinding.captureImageCameraPreview.setVisibility(View.GONE); mActivityCaptureImagesBinding.imvPreview.setVisibility(View.VISIBLE); }); } catch (Exception e) { Log.e(TAG_IMAGES_CAPTURE, "Exception while showHidePreviewScreen : " + e.getMessage()); } }
问题根源
- 错误的图像获取方式:代码中通过
PreviewView.getBitmap()获取拍摄后的图片,而PreviewView的预览画面是经过裁剪、适配控件尺寸后的结果,和ImageCapture实际捕获的原始图像分辨率、比例不一致,导致显示时出现黑条。 - 固定旋转角度不合理:硬编码
setTargetRotation(Surface.ROTATION_0),没有跟随设备的实际旋转状态,可能导致画面方向与预览不匹配,进一步引发显示适配问题。
解决方案
1. 从ImageProxy获取原始图像
放弃从PreviewView取图,直接使用ImageCapture回调中返回的ImageProxy,转换为Bitmap后再显示。
2. 适配设备实际旋转角度
通过previewView.getDisplay().getRotation()获取当前设备旋转角度,设置给ImageCapture,保证拍摄方向与预览一致。
修改后的代码示例
// 初始化ImageCapture时,替换固定旋转为设备实际旋转 ImageCapture imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) .setTargetResolution(new Size(1280, 720)) .setTargetRotation(previewView.getDisplay().getRotation()) .build(); // 修改拍照回调逻辑 mActivityCaptureImagesBinding.imbCapture.setOnClickListener(v -> { imageCapture.takePicture(Runnable::run, new ImageCapture.OnImageCapturedCallback() { @Override public void onCaptureSuccess(ImageProxy imageProxy) { // 将ImageProxy转换为Bitmap Image image = imageProxy.getImage(); if (image != null) { bmpCaptured = toBitmap(image); // 注意关闭ImageProxy释放资源 imageProxy.close(); showHidePreviewScreen(); } } @Override public void onError(ImageCaptureException exception) { Log.e(TAG_IMAGES_CAPTURE, "Exception while taking image : " + exception.getMessage()); } }); }); // 添加Image转Bitmap的工具方法 private Bitmap toBitmap(Image image) { Image.Plane[] planes = image.getPlanes(); ByteBuffer yBuffer = planes[0].getBuffer(); ByteBuffer uBuffer = planes[1].getBuffer(); ByteBuffer vBuffer = planes[2].getBuffer(); int ySize = yBuffer.remaining(); int uSize = uBuffer.remaining(); int vSize = vBuffer.remaining(); byte[] nv21 = new byte[ySize + uSize + vSize]; yBuffer.get(nv21, 0, ySize); vBuffer.get(nv21, ySize, vSize); uBuffer.get(nv21, ySize + vSize, uSize); YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null); ByteArrayOutputStream out = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 100, out); byte[] imageBytes = out.toByteArray(); return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); }
说明
- 从
ImageProxy获取的是相机捕获的原始图像,不存在预览适配的裁剪问题,能保证画面完整。 - 动态获取设备旋转角度,确保拍摄方向与预览一致,避免因角度不匹配导致的画面拉伸或黑条。
内容的提问来源于stack exchange,提问作者Sandip Armal Patil
相关产品推荐
相关产品推荐

