求助:Camera View库在三星等设备拍照图片旋转异常,需按拍摄原样显示
解决Camera View库在三星设备上的图片旋转问题
我之前在项目里用Camera View库时,也碰到过三星这类设备上图片旋转异常的问题——明明拍摄时是竖屏,结果显示出来却是横屏,折腾了好一阵才搞定!结合你的情况,给你一套可行的手动处理旋转的方案,应该能解决你的问题:
一、先搞清楚两个核心角度
要正确旋转图片,得先算出两个关键值:设备的当前旋转角度和相机传感器的固有方向,两者结合才能得到最终需要旋转的角度。
1. 获取设备的显示旋转角度
这个值对应用户手持设备的实际方向:
private int getDeviceRotationDegrees() { int rotation = getWindowManager().getDefaultDisplay().getRotation(); switch (rotation) { case Surface.ROTATION_0: return 0; case Surface.ROTATION_90: return 90; case Surface.ROTATION_180: return 180; case Surface.ROTATION_270: return 270; default: return 0; } }
2. 获取相机传感器的固有方向
不同相机(前置/后置)的传感器方向是硬件固定的,大部分手机后置是90度,但三星等设备可能有差异,必须动态获取:
private int getCameraSensorOrientation(String cameraId) throws CameraAccessException { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); }
二、计算最终需要旋转的角度
把上面两个值结合,还要区分前置/后置相机(前置需要处理镜像逻辑):
private int calculateRequiredRotation() { int deviceRotation = getDeviceRotationDegrees(); String cameraId = cameraView.getCameraId(); // 从Camera View获取当前使用的相机ID,不要硬编码 int sensorOrientation = 0; try { sensorOrientation = getCameraSensorOrientation(cameraId); } catch (CameraAccessException e) { e.printStackTrace(); } // 区分前置/后置相机,计算最终旋转角度 boolean isFrontCamera = cameraId.equals("1"); // 大部分设备前置相机ID是1,根据实际情况调整 if (isFrontCamera) { // 前置相机需要额外处理镜像,这里先计算旋转角度 return (sensorOrientation + deviceRotation) % 360; } else { return (sensorOrientation - deviceRotation + 360) % 360; } }
三、拍摄后手动旋转Bitmap
在Camera View的拍照回调里,拿到原始图片后,用上面算出的角度旋转Bitmap,再显示:
cameraView.takePicture(new CameraView.PictureCallback() { @Override public void onPictureTaken(CameraView cameraView, byte[] data) { // 解码原始图片 Bitmap originalBitmap = BitmapFactory.decodeByteArray(data, 0, data.length); // 计算需要旋转的角度 int requiredRotation = calculateRequiredRotation(); // 旋转图片 Bitmap rotatedBitmap = rotateBitmap(originalBitmap, requiredRotation); // 处理前置相机的镜像问题(如果需要) boolean isFrontCamera = cameraView.getCameraId().equals("1"); if (isFrontCamera) { rotatedBitmap = flipBitmapHorizontally(rotatedBitmap); } // 显示处理后的图片 yourImageView.setImageBitmap(rotatedBitmap); // 释放原始Bitmap内存,避免OOM if (originalBitmap != null && !originalBitmap.isRecycled()) { originalBitmap.recycle(); } } }); // 旋转Bitmap的工具方法 private Bitmap rotateBitmap(Bitmap bitmap, int degrees) { if (degrees == 0 || bitmap == null) { return bitmap; } Matrix matrix = new Matrix(); matrix.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); try { return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } catch (OutOfMemoryError e) { e.printStackTrace(); return bitmap; } } // 水平翻转Bitmap(前置相机需要) private Bitmap flipBitmapHorizontally(Bitmap bitmap) { Matrix matrix = new Matrix(); matrix.postScale(-1, 1); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); }
四、保存图片时记得设置Exif信息
如果需要把图片保存到本地,一定要设置Exif旋转信息,这样其他应用打开图片时也能正确显示:
private void saveRotatedBitmap(Bitmap bitmap, int rotationDegrees, String savePath) { FileOutputStream out = null; try { out = new FileOutputStream(savePath); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); // 设置Exif旋转属性 ExifInterface exif = new ExifInterface(savePath); int exifOrientation = convertRotationToExif(rotationDegrees); exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(exifOrientation)); exif.saveAttributes(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (out != null) out.close(); } catch (IOException e) { e.printStackTrace(); } } } // 把旋转角度转换成Exif对应的常量 private int convertRotationToExif(int rotationDegrees) { switch (rotationDegrees) { case 0: return ExifInterface.ORIENTATION_NORMAL; case 90: return ExifInterface.ORIENTATION_ROTATE_90; case 180: return ExifInterface.ORIENTATION_ROTATE_180; case 270: return ExifInterface.ORIENTATION_ROTATE_270; default: return ExifInterface.ORIENTATION_NORMAL; } }
额外注意事项
- 优先更新Camera View库:先检查一下你用的库是不是最新版本,说不定官方已经修复了三星设备的兼容问题,能省不少事。
- 相机ID不要硬编码:不同设备的前置/后置相机ID可能不一样,一定要用Camera View提供的
getCameraId()方法获取。 - 内存优化:旋转Bitmap会占用额外内存,记得及时回收原始Bitmap,避免内存溢出。
内容的提问来源于stack exchange,提问作者Moustafa EL-Saghier




