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




