将相册中图片显示ImageView时,图片发生旋转以及java.io.FileNotFoundException:图片路径 (Permission denied)

为了实现点击按钮,从相册中获取选取图片显示在ImageView这个功能可谓是一波多折。。。。。
最初是无法实现此功能,在网上找到了如下代码。

第一版

 /**
     * 从本地选择文件
     *
     * @param view
     */
    public void chooseLocalImage(View view) {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent, ACTION_CHOOSE_IMAGE);
    }

实现将图片显示在ImageView中。

 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ACTION_CHOOSE_IMAGE) {
            if (data == null || data.getData() == null) {
                Toast.makeText(this, R.string.get_picture_failed, Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                mBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
            if (mBitmap == null) {
                Toast.makeText(this, R.string.get_picture_failed, Toast.LENGTH_SHORT).show();
                return;
            }
            Glide.with(ivShow.getContext())
                    .load(mBitmap)
                    .into(ivShow);
        }
    }

这个功能在相册中选择图片时,有的图片是经过旋转的,然后,又是各种搜百度,最后知道,问题的根源在于存储在手机相册里面的图片的方向有了角度导致显示不正。

第二版

最后的解决方案是:(添加如下代码)

int degree = util.readPictureDegree(getRealPathFromURI(data.getData()));
mBitmap = util.rotaingImageView(degree, mBitmap);

添加之后的代码如下:

 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ACTION_CHOOSE_IMAGE) {
            if (data == null || data.getData() == null) {
                Toast.makeText(this, R.string.get_picture_failed, Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                mBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());


                //新加的代码
                int degree = util.readPictureDegree(getRealPathFromURI(data.getData()));
                mBitmap = util.rotaingImageView(degree, mBitmap);


            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
            if (mBitmap == null) {
                Toast.makeText(this, R.string.get_picture_failed, Toast.LENGTH_SHORT).show();
                return;
            }
            Glide.with(ivShow.getContext())
                    .load(mBitmap)
                    .into(ivShow);
        }
    }

图中有阴影的地方,就是新增的代码
新增代码的位置图片
其中readPictureDegree方法和rotaingImageView方法以及getRealPathFromURI方法如下:

 /**
      * 读取图片属性:旋转的角度
      * @param path 图片绝对路径
      * @return degree旋转的角度
     **/
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
                ExifInterface exifInterface = new ExifInterface(path);
                int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                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 Bitmap
     **/
    public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
        //旋转图片 动作
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        System.out.println("angle2=" + angle);
        // 创建新的图片
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizedBitmap;
    }


 /**
     * 根据Uri获取图片的真实路径
     *
     * @param contentURI 图片的Uri
     * @return 图片的在手机中存储路径
     */
    String getRealPathFromURI(Uri contentURI) {
        String result;
        Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
        //不能直接调用contentprovider的接口函数,需要使用contentresolver对象,通过URI间接调用contentprovider
        if (cursor == null) {
            // Source is Dropbox or other similar local file path
            result = contentURI.getPath();
        } else {
            cursor.moveToFirst();
            int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            result = cursor.getString(idx);
            cursor.close();
        }
        return result;
    }

第三版

然后用了一段时间后,当我想完善这个功能的时候,发现此功能又出现问题了。。。。在第二版中获取到的角度都是0,并且报错
java.io.FileNotFoundException:此处是图片路径 (Permission denied)
是无法获取手机内存的权限。在手机上安装的app的应用权限上也显示未获取到存储空间的权限,如下图所示。
权限图片
之后冷静下来才想到,在出现问题后,在调用显示图片的activity时,手机不在出现有关存储空间权限的询问。又是一顿找度娘,最后找到了如下解决方案:
(实现询问用户是否授予此软件拥有操作存储空间的权限)

 util.isGrantExternalRW(SingleImageActivity.this);

使用例子如图所示:(我是在页面完成刚完成初始化后,就开始询问用户)
例子

isGrantExternalRW方法如下:

/**
     * 解决安卓6.0以上版本不能读取外部存储权限的问题
     * @param activity
     * @return
     */
    public static boolean isGrantExternalRW(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            activity.requestPermissions(new String[]{
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            }, 1);
            return false;
        }
        return true;
    }

终于算是成功的完成此功能了,有点啰嗦,但是很实用,希望遇到此问题的小伙伴们可以认真的看完这篇博客,也希望此篇博客能帮助一些和我遇到相同困难的小伙伴们。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值