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

求助: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

火山引擎 最新活动