You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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());
    }
}

问题根源

  1. 错误的图像获取方式:代码中通过PreviewView.getBitmap()获取拍摄后的图片,而PreviewView的预览画面是经过裁剪、适配控件尺寸后的结果,和ImageCapture实际捕获的原始图像分辨率、比例不一致,导致显示时出现黑条。
  2. 固定旋转角度不合理:硬编码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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:35:19