android Camare获取照片,角度旋转90度,用ExifInterface类获取角度为0

解决拍照角度偏移问题
本文介绍了一种解决使用自定义相机拍照时照片角度偏移的方法。通过直接利用CameraInfo中的orientation属性,避免了ExifInterface无法正确读取角度的问题。

问题:用自定义相机,使用Camare.takePicture()方法获取照片,发现照片的角度硬生生被转了90度。在网上一翻查找,发现90%的博客都是说用下面这种办法:先用ExifInterface类得到照片的角度参数,然后再将照片角度转回来。

/**
     * 读取照片旋转角度
     *
     * @param path 照片路径
     * @return 角度
     */
    public int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            Log.i("tag", "读取角度-" + orientation);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋转图片
     *
     * @param angle  被旋转角度
     * @param bitmap 图片对象
     * @return 旋转后的图片
     */
    public Bitmap rotaingImageView(int angle, Bitmap bitmap) {
        Bitmap returnBm = null;
        // 根据旋转角度,生成旋转矩阵
        Matrix matrix = new Matrix();
        matrix.postRotate(-angle);
        try {
            // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
            returnBm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
        }
        if (returnBm == null) {
            returnBm = bitmap;
        }
        if (bitmap != returnBm) {
            bitmap.recycle();
        }
        return returnBm;
    }

确实这种方法可能其他人都有用,但是对我确实没用(好蛋疼~~~)。主要是因为不论我用什么角度拍照片,用ExifInterface类获取到的照片角度一直为0,所以再调用rotaingImageView()想把照片角度转回来就根本没效果。
然后又是一番查找,发现了这个博客:https://blog.youkuaiyun.com/zhjali123/article/details/46986467 用其方法真的解决了自己的问题。下面贴出我的代码

camera.takePicture(null, null, new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
    //获取图片时
    Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
    android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
    android.hardware.Camera.getCameraInfo(0, info);//得到Camera相机信息
    Bitmap bitmap = rotaingImageView(info.orientation, realImage);//通过得到的相机信息中orientation角度,再旋转照片角度
    bitmap = ThumbnailUtils.extractThumbnail(bitmap, 240, 320);//裁剪照片尺寸
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    photoData = stream.toByteArray();
    createFileWithByte(photoData);//保存照片
    }
});
/**
* 根据byte数组生成文件
*
* @param bytes 生成文件用到的byte数组
*/
private void createFileWithByte(byte[] bytes) {
    // TODO Auto-generated method stub
    /**
    * 创建File对象,其中包含文件所在的目录以及文件的命名
    */
    String file_directory = Environment.getExternalStorageDirectory();
    File imgfile = new File(file_directory, getPicName());
    // 创建FileOutputStream对象
    FileOutputStream outputStream = null;
    // 创建BufferedOutputStream对象
    BufferedOutputStream bufferedOutputStream = null;
    try {
        File file = new File(file_directory);
        //判断文件夹是否存在,如果不存在则创建文件夹
        if (!file.exists()) {
            file.mkdir();
        }
        // 如果文件存在则删除
        if (imgfile.exists()) {
            imgfile.delete();
        }
        // 在文件系统中根据路径创建一个新的空文件
        imgfile.createNewFile();
        // 获取FileOutputStream对象
        outputStream = new FileOutputStream(imgfile);
        // 获取BufferedOutputStream对象
        bufferedOutputStream = new BufferedOutputStream(outputStream);
        // 往文件所在的缓冲输出流中写byte数据
        bufferedOutputStream.write(bytes);
        // 刷出缓冲输出流,该步很关键,要是不执行flush()方法,那么文件的内容是空的。
        bufferedOutputStream.flush();
    } catch (Exception e) {
        // 打印异常信息
        e.printStackTrace();
    } finally {
        // 关闭创建的流对象
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bufferedOutputStream != null) {
            try {
                bufferedOutputStream.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }   
        }    
    }
}
在 UniApp 中实现调用相机进行扫码功能,主要依赖于 `uni.scanCode` API 或结合第三方库(如 `qrcode.js`)来解析二维码。根据不同的平台(H5、APP、小程序等),实现方式会略有不同。 ### 使用 `uni.scanCode` 实现扫码功能 这是 UniApp 官方提供的 API,适用于 APP 和部分小程序平台。它可以直接调用设备的摄像头进行扫码操作,并返回结果。 #### 示例代码: ```javascript // 调用扫码功能 uni.scanCode({ success: function (res) { console.log('扫码成功:', res.result); // 处理扫码后的逻辑,例如跳转页面或展示数据 }, fail: function (err) { console.error('扫码失败:', err); uni.showToast({ title: '扫码失败,请重试', duration: 2000, icon: 'none' }); } }); ``` 此方法需要确保应用已经获取了相机权限。对于 Android 平台,还需要在 `manifest.json` 文件中配置相机权限 [^1]。 --- ### H5 端实现扫码功能 由于 H5 环境下无法直接使用 `uni.scanCode`,因此可以借助第三方插件或者手动引入 `qrcode.js` 来实现扫码功能。 #### 使用 `qrcode.js` 解析二维码图片 该方案通过调用 `uni.chooseImage` 获取用户选择的二维码图片,再利用 `qrcode.js` 进行解码。 ##### 示例代码: ```html <template> <view class="container"> <u-icon name="scan" size="100" @click="scanCode"></u-icon> </view> </template> <script> var qrcode = require('../../static/js/qrcode.js'); export default { methods: { scanCode() { let that = this; uni.chooseImage({ count: 1, success: function(res) { const tempFilePaths = res.tempFilePaths[0]; qrcode.decode(tempFilePaths); qrcode.callback = function(result) { if (result === "error decoding QR Code") { uni.showToast({ title: "识别二维码失败,请重新上传!", duration: 2000, icon: 'none' }); } else { console.log("识别结果:", result); // 可以在此处处理跳转或其他业务逻辑 } }; } }); } } }; </script> ``` 需要注意的是,H5 端的扫码功能仅在 HTTPS 环境下有效,否则可能会出现兼容性问题 [^3]。 --- ### 自定义扫码界面 如果你希望自定义扫码界面(如添加扫描框、手电筒开关、提示文字等),可以使用原生插件或基于 `plus.camera` 的方式实现更复杂的交互体验。这种方式适合对 UI/UX 有较高要求的应用场景。 #### 示例代码(APP 端): ```javascript const camera = plus.camera.getCamera(); camera.startCapture(function(path) { console.log("拍照成功:" + path); qrcode.decode(path); // 使用 qrcode.js 解码 }, function(e) { console.log("拍照失败:" + e.message); }); ``` 此外,还可以通过监听点击事件开启手电筒功能,提升黑暗环境下的扫码体验 [^2]。 --- ### 常见问题与注意事项 - **权限问题**:在 Android 设备上,必须在 `manifest.json` 中申请相机权限;iOS 上也需要在 `info.plist` 中添加相关描述。 - **HTTPS 环境限制**:H5 页面必须部署在 HTTPS 服务器上才能正常调用摄像头 [^4]。 - **兼容性问题**:不同平台对扫码的支持程不一致,建议针对目标平台做充分测试。 - **连续扫码支持**:如果需要实现连续扫码功能,可能需要自行封装循环调用 `uni.scanCode` 的逻辑。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值