You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android 10下使用Camera2 API调用前置摄像头拍照的图像方向异常问题

解决Android 10上Camera2 API前置摄像头图像方向异常问题

我之前也碰到过一模一样的情况——升级到Camera2 API后,前置摄像头拍的图在Android 5、9上方向都正常,偏偏Android 10就出问题。咱们来拆解下可能的原因,然后给出可行的解决方案:

一、先分析原代码的问题点

你之前用的方向计算逻辑:

int jpegOrientation = (ORIENTATIONS.get(rotation) + characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) + 270) % 360;
capturebuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation);

这个逻辑在大部分系统版本里没问题,但Android 10对前置摄像头的JPEG方向处理做了细微调整,尤其是前置摄像头默认的镜像特性,之前的计算没有针对性适配,导致方向异常。

二、针对性调整方向计算逻辑

前置摄像头和后置的方向计算逻辑是有区别的,因为前置是镜像输出,我们需要单独处理:

// 获取设备当前旋转角度
int deviceRotation = getWindowManager().getDefaultDisplay().getRotation();
// 获取摄像头传感器方向
int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
int jpegOrientation;

// 判断是否是前置摄像头
if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
    // 前置摄像头需要考虑镜像,调整方向计算
    jpegOrientation = (ORIENTATIONS.get(deviceRotation) + sensorOrientation) % 360;
    // 反转角度来适配镜像后的方向
    jpegOrientation = (360 - jpegOrientation) % 360;
} else {
    // 后置摄像头沿用原来的逻辑
    jpegOrientation = (ORIENTATIONS.get(deviceRotation) + sensorOrientation + 270) % 360;
}

// 应用到CaptureRequest
capturebuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation);

这个调整主要是给前置摄像头单独加了镜像方向的补偿,你可以先测试这个方案,大部分Android 10的场景下应该能解决问题。

三、如果上述方案无效,试试手动旋转Bitmap(通用方案)

如果系统层面的JPEG_ORIENTATION设置在Android 10上依然不生效,我们可以在拿到图片数据后,手动读取Exif信息并旋转Bitmap,同时处理前置的镜像:

// 假设你已经获取到拍摄后的图片byte数组data
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
ExifInterface exif = new ExifInterface(inputStream);
// 读取Exif中的方向信息
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

// 转换为旋转角度
int rotationDegrees = 0;
switch (exifOrientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        rotationDegrees = 90;
        break;
    case ExifInterface.ORIENTATION_ROTATE_180:
        rotationDegrees = 180;
        break;
    case ExifInterface.ORIENTATION_ROTATE_270:
        rotationDegrees = 270;
        break;
}

// 前置摄像头额外处理镜像翻转
boolean isFrontCamera = (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT);
if (isFrontCamera) {
    rotationDegrees = (rotationDegrees + 180) % 360;
}

// 旋转并(可选)镜像Bitmap
Matrix matrix = new Matrix();
matrix.setRotate(rotationDegrees);
if (isFrontCamera) {
    matrix.postScale(-1, 1); // 水平翻转实现镜像效果
}

Bitmap originalBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap rotatedBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth(), originalBitmap.getHeight(), matrix, true);

// 显示到ImageView
imageView.setImageBitmap(rotatedBitmap);

这种方式绕开了系统Camera2参数的差异,直接在图片数据层面处理,兼容性更好,不受系统版本限制。

额外注意点

  • 确保你的ORIENTATIONS映射表是正确的,比如:
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 0);
        ORIENTATIONS.append(Surface.ROTATION_90, 90);
        ORIENTATIONS.append(Surface.ROTATION_180, 180);
        ORIENTATIONS.append(Surface.ROTATION_270, 270);
    }
    
  • 检查CaptureRequest.Builder的设置时机,确保在创建后立刻设置JPEG_ORIENTATION,没有被后续的代码覆盖。

内容的提问来源于stack exchange,提问作者konda rahul

火山引擎 最新活动