Camera2 API图像旋转异常:Nokia 6.1竖拍照片显示为横屏
我之前处理过类似Android One设备的Camera2 API方向适配问题,结合你描述的情况——已经尝试了两种标准的JPEG_ORIENTATION计算方法,返回值都是90但在Nokia 6.1上完全无效,其他设备正常——大概率是这款设备的Camera Provider实现对CaptureRequest.JPEG_ORIENTATION参数的处理有特殊逻辑,或者EXIF元数据的写入/解析存在差异。下面给你几个针对性的解决方案:
先排查核心原因:确认传感器方向和EXIF数据
在动手调整代码前,先做两个小检查,帮你定位问题:
- 打印传感器方向:Nokia 6.1的相机传感器方向可能和你预期的不同,比如不是常见的90或270。在获取
CameraCharacteristics时加一行日志:
如果这个值不是90,那你之前的方向计算逻辑就需要调整。CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String cameraId = "你的相机ID"; // 比如后置相机ID CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); Log.d("CamDebug", "Nokia 6.1 Sensor Orientation: " + sensorOrientation); - 检查EXIF信息:用文件管理器查看拍摄后的JPEG照片的EXIF属性,看
Orientation字段是否是90。如果这个字段是0或者其他值,说明相机根本没把你设置的JPEG_ORIENTATION写入EXIF,这就是ImageView显示横屏的原因。
解决方案1:手动读取EXIF并旋转Bitmap显示
既然相机可能没正确写入EXIF,或者ImageView没正确解析,咱们就手动处理:
// 工具方法:根据EXIF旋转Bitmap public static Bitmap getRotatedBitmapFromPath(String photoPath) { Bitmap rawBitmap = BitmapFactory.decodeFile(photoPath); if (rawBitmap == null) return null; ExifInterface exif; try { exif = new ExifInterface(photoPath); } catch (IOException e) { e.printStackTrace(); return rawBitmap; } int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); Matrix matrix = new Matrix(); switch (exifOrientation) { case ExifInterface.ORIENTATION_ROTATE_90: matrix.postRotate(90); break; case ExifInterface.ORIENTATION_ROTATE_180: matrix.postRotate(180); break; case ExifInterface.ORIENTATION_ROTATE_270: matrix.postRotate(270); break; default: return rawBitmap; } return Bitmap.createBitmap(rawBitmap, 0, 0, rawBitmap.getWidth(), rawBitmap.getHeight(), matrix, true); }
然后在ImageView中使用这个方法:
ImageView photoView = findViewById(R.id.your_image_view); Bitmap rotatedBitmap = getRotatedBitmapFromPath("你的照片路径"); if (rotatedBitmap != null) { photoView.setImageBitmap(rotatedBitmap); }
解决方案2:强制同时设置JPEG_ORIENTATION和EXIF参数
有些Android One设备需要显式设置EXIF方向参数,即使文档说JPEG_ORIENTATION会自动控制它。试试在构建CaptureRequest.Builder时添加一行:
int calculatedOrientation = 你的计算结果; // 比如90 captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, calculatedOrientation); // 额外添加这一行,强制写入EXIF方向 captureRequestBuilder.set(CaptureRequest.JPEG_EXIF_ORIENTATION, calculatedOrientation);
这样能确保相机硬件同时处理JPEG旋转和EXIF元数据写入。
解决方案3:手动旋转图像数据(如果前面方法都无效)
如果Nokia 6.1的相机完全忽略了方向参数,那咱们直接在图像输出环节手动旋转:
用ImageReader获取原始JPEG数据,解码成Bitmap后旋转再保存:
// 初始化ImageReader时注意尺寸(竖屏时可能需要交换宽高?) ImageReader imageReader = ImageReader.newInstance(竖屏宽度, 竖屏高度, ImageFormat.JPEG, 1); imageReader.setOnImageAvailableListener(reader -> { Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] jpegData = new byte[buffer.remaining()]; buffer.get(jpegData); // 解码并旋转 Bitmap rawBitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length); Matrix rotateMatrix = new Matrix(); rotateMatrix.postRotate(90); // 根据你的需要设置旋转角度 Bitmap rotatedBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, rawBitmap.getWidth(), rawBitmap.getHeight(), rotateMatrix, true); // 保存旋转后的图像 try (FileOutputStream fos = new FileOutputStream("你的输出文件路径")) { rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); } catch (IOException e) { e.printStackTrace(); } image.close(); }, null);
这种方法虽然麻烦,但能彻底绕开设备的Camera2 API适配问题。
总结
Nokia 6.1作为Android One设备,厂商对Camera2 API的实现可能更贴近原生但有特殊处理,优先尝试解决方案1(手动处理EXIF旋转),这是最通用的适配方式;如果还是不行,再试试显式设置EXIF参数或者手动旋转图像数据。
内容的提问来源于stack exchange,提问作者Manuj Jagga

