Android开发必知-图片拍照,选择,裁剪,压缩(适配高版本)

ps:这篇文章只是整理偏常规的图片开发知识点。下面走起~

拍照

7.0之前,我们设置拍照保存的文件地址的 Uri,都是直接Intent.putExtra(MediaStore.EXTRA_OUTPUT,文件保存的Uri路径),但是 7.0之后,对用户权限提高了保护,之前那种方式行不通了,所以我们要做7.0的判断,用 FileProvider 获取设置保存的文件 Uri,然后放到Intent.putExtra(MediaStore.EXTRA_OUTPUT,文件保存的Uri路径)中,代码如下:

        //相机拍照的一个标识,后面用
        TAKEPAHTO = 1;
        // 启动系统相机
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //7.0以下设置保存图片的地址
        Uri norTakePhotoSaveAdr;
        // 判断7.0android系统
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //临时添加一个拍照权限
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //  //通过FileProvider获取保存图片file的uri(先创建file,然后获取File的Uri)
            takePhotoSaveAdr = FileProvider.getUriForFile(MainActivity.this,
                    "com.hxzk.bj.photodemo", new File(Environment.getExternalStorageDirectory(), "savephoto.jpg"));
            //MediaStore.EXTRA_OUTPUT-此设置需要一个保存图片的路径和文件名的Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, takePhotoSaveAdr);
        } else {
            norTakePhotoSaveAdr = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "savephoto.jpg"));
            intent.putExtra(MediaStore.EXTRA_OUTPUT, norTakePhotoSaveAdr);
        }
        //PHOTO_TAKEPHOTO,相机的一个请求码,返回时要用
        startActivityForResult(intent, PHOTO_TAKEPHOTO);

相册图片选取

这块主要是Action的取用,直接上代码:

                //拍照的一个表示
                TAKEPAHTO = 0;
                //调用系统图库,选择图片
                //Intent.ACTION_PICK 意思是选择数据,其具体表达有:
                // Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                //intent.setType("image/*"); 获取本地图片
                // intent.setType("video/*");  获取本地视频
                //intent.setType("audio/*")  获取本地音乐

                // Intent intent = new Intent(Intent.ACTION_PICK);
                //  intent.setType(ContactsContract.Contacts.CONTENT_TYPE); //获取联系人
                // startActivityForResult(intent, PICK_CONTACT);

                //第二种写法
                Intent intent = new Intent(Intent.ACTION_PICK, null);
                //其中External为sdcard下的多媒体文件,Internal为system下的多媒体文件。
                //使用INTERNAL_CONTENT_URI只能显示存储在内部的照片
                intent.setDataAndType(
                        MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
                //返回结果和标识
                startActivityForResult(intent, PHOTO_PHOTOALBUM);

接着,不论是拍照还是选取图片,我们都要在Activity的onActivityResult中去获取返回结果,然后进行下一步操作。这里提一下,我们在跳转相册或拍照都有一个requestCode,我们全局定义了三个,分别是拍照,相册,裁剪的标识:

    //图库
    private static final int PHOTO_PHOTOALBUM = 0;
    //拍照
    private static final int PHOTO_TAKEPHOTO = 1;
    //裁剪
    private static final int PHOTO_PHOTOCLIP = 2;

在onActivityResult中就要用来区分了:

if (resultCode == RESULT_OK) {//避免选图时取消操作
            switch (requestCode) {
                case PHOTO_TAKEPHOTO:
                    Uri clipUri;
                    //判断如果是7.0
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        clipUri = takePhotoSaveAdr;
                    } else {
                        clipUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/savephoto.jpg"));
                    }
                    //获取拍照结果,执行裁剪
                    startPhotoZoom(clipUri);
                    break;
                case PHOTO_PHOTOALBUM:

                    //获取图库结果,执行裁剪
                    startPhotoZoom(data.getData());


                    break;
                case PHOTO_PHOTOCLIP:
                    //注:glide版本 >=4.4 加载同一个图片,地址不变,会有缓存,加载的还是之前的一张
                    //裁剪完成后的操作,上传至服务器或者本地设置
                    RequestOptions optionsa = new RequestOptions();
                    optionsa.placeholder(R.mipmap.ic_launcher);
                    optionsa.error(R.mipmap.ic_launcher_round);    //异常显示图
                    optionsa.diskCacheStrategy(DiskCacheStrategy.NONE);//禁用掉Glide的缓存功能
                    optionsa.skipMemoryCache(true);//禁用掉Glide的内存缓存
                    Glide.with(this).load(uriClipUri).apply(optionsa).into(ivUserPhoto);

                    break;
            }
        }

裁剪

图片的裁剪我们主要看一下starPhotoZoom()这个裁剪方法,思路是通过设置Intent,调用的是系统的裁剪工具,代码如下:

/**
     * 图片裁剪的方法
     *
     * @param uri
     */
    public void startPhotoZoom(Uri uri) {
        Log.e("uri=====", "" + uri);
        //com.android.camera.action.CROP,这个action是调用系统自带的图片裁切功能
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");//裁剪的图片uri和图片类型
        intent.putExtra("crop", "true");//设置允许裁剪,如果不设置,就会跳过裁剪的过程,还可以设置putExtra("crop", "circle")
        intent.putExtra("aspectX", 1);//裁剪框的 X 方向的比例,需要为整数
        intent.putExtra("aspectY", 1);//裁剪框的 Y 方向的比例,需要为整数
        intent.putExtra("outputX", 60);//返回数据的时候的X像素大小。
        intent.putExtra("outputY", 60);//返回数据的时候的Y像素大小。
        //uriClipUri为Uri类变量,实例化uriClipUri
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (TAKEPAHTO == 1) {//如果是7.0的拍照
                //开启临时访问的读和写权限
                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                //针对7.0以上的操作
                intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri));
                uriClipUri = uri;
            } else {//如果是7.0的相册
                //设置裁剪的图片地址Uri
                uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg");
            }

        } else {
            uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg");
        }
        Log.e("uriClipUri=====", "" + uriClipUri);
        //Android 对Intent中所包含数据的大小是有限制的,一般不能超过 1M,否则会使用缩略图 ,所以我们要指定输出裁剪的图片路径
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uriClipUri);
        intent.putExtra("return-data", false);//是否将数据保留在Bitmap中返回
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//输出格式,一般设为Bitmap格式及图片类型
        intent.putExtra("noFaceDetection", true);//人脸识别功能
        startActivityForResult(intent, PHOTO_PHOTOCLIP);//裁剪完成的标识

    }

压缩

裁剪完后,再做下压缩操作,主要借助BitmapFactory类,上代码:

/**
     * 图片压缩的方法(只是内存减少,避免oom,图片本身在disk盘体积不变)
     * 显示的Bitmap占用的内存少一点,还是需要去设置加载的像素长度和宽度(变成缩略图)
     */
    public void compressPhto(File mFile){
//        BitmapFactory这个类就提供了多个解析方法(decodeResource、decodeStream、decodeFile等)用于创建Bitmap。
//        比如如果图片来源于网络,就可以使用decodeStream方法;
//        如果是sd卡里面的图片,就可以选择decodeFile方法;
//        如果是资源文件里面的图片,就可以使用decodeResource方法等
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; // 获取当前图片的边界大小
        //BitmapFactory.decodeResource(getResources(), R.drawable.bg, options);
        BitmapFactory.decodeFile(mFile.getAbsolutePath(),options);
        int outHeight = options.outHeight; //获取图片本身的高像素
        int outWidth = options.outWidth;//获取图片本身的宽的像素
        String outMimeType = options.outMimeType;
        options.inJustDecodeBounds = false;
        //inSampleSize的作用就是可以把图片的长短缩小inSampleSize倍,所占内存缩小inSampleSize的平方
        //对于inSampleSize值的大小有要求,最好是整数且2的倍数
        options.inSampleSize = caculateSampleSize(options, 500, 500);
        //etPath()得到的是构造file的时候的路径。getAbsolutePath()得到的是全路径
        String path =mFile.getPath();
        String absPath=mFile.getAbsolutePath();
        Bitmap bitmap = BitmapFactory.decodeFile(absPath,options);
        ivUserPhoto.setImageBitmap(bitmap);
        //尺寸压缩结果
        ivSize.setImageBitmap(bitmap);
    }

    /**
     * 计算出所需要压缩的大小
     * @param options
     * @param reqWidth  希望的图片宽大小
     * @param reqHeight 希望的图片高大小
     * @return
     */
    private int caculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        int sampleSize = 1;
        int picWidth = options.outWidth;
        int picHeight = options.outHeight;
        if (picWidth > reqWidth || picHeight > reqHeight) {
            int halfPicWidth = picWidth / 2;
            int halfPicHeight = picHeight / 2;
            while (halfPicWidth / sampleSize > reqWidth || halfPicHeight / sampleSize > reqHeight) {
                sampleSize *= 2;
            }
        }
        return sampleSize;
    }

结束!!!

猜你喜欢

转载自blog.csdn.net/CallmeZhe/article/details/111772727