指定Uri文件图片进行压缩,如何避开OOM?

  • 前言

图片压缩与二次采样

为什么要压缩图片?

可以试想:当一个App调用系统的相机进行拍照操作时,如果我们从Intent中获取的data数据设置给图片时,它仅仅显示的是一张略缩图(120x160 宽高),并不能满足我们的需求!于是我们在startActivity()的时候putExtra()指定一个存储路径,获取Uri指定路径下的图片, 在config为ARGB_8888的情况下,每个像素要占用四个字节,一张图片通常会达到3xxx x 4xxx 这样一个级别,计算出来之后 会达到一个几十M的级别 60M,因为默认情况下系统中的每个App只享有16m的独立内存,这样很容易把内存加爆了,所以压缩图片十分重要!

图片压缩的流程

  • 核心

  • 我们加载的时候使用带options参数的方法去加载

  • 在options中我们指定inJustDecodeBounds为true,仅解码边缘,这样图片不会真正的被加载到内存中,图片的基本信息,比如宽,高会被加载到内存中
  • 压缩比例,采样比例值是2的n次幂,向下取整
  • 根据我们想要的宽高和图片的宽高计算一个压缩比例,设置到options上
  • 关闭仅解码边缘,重新进行解码

获取指定路径的原图

启动相机的时候传值

private void takePicSave() {
        Intent intent = new Intent();

        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //保存 EXTRA_OUTPUT:将拍摄的图片保存到指定uri路径
        mUri = getUri();

        intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);

        this.startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE_SAVE);

获取指定路径的文件

private Uri getUri() {

        if(ActivityCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED){

            if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                //DCIM
                File root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);

                long time = System.currentTimeMillis();

                File picFile = new File(root,time+".jpg");

                return Uri.fromFile(picFile);
            }else {
                File root = this.getCacheDir();
                long time = System.currentTimeMillis();
                return Uri.parse("file://"+root.getAbsolutePath()+File.separator+time+".jpg");
            }
        }else {
            //申请读写内存卡权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
                            Manifest.permission.READ_EXTERNAL_STORAGE},
                    REQUEST_CODE_EXTERNAL);
        }
        return null;
    }

图片的压缩与二次采样

public Bitmap sampleImage(String filePath){

        BitmapFactory.Options options = new BitmapFactory.Options();
        // 设置仅解码边缘,图片不会真正加载到内存中,解码器加载返回null,
        // 但是图片的输出字段会进行赋值
        // 比如说 图片的宽,高
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(filePath, options);

        int outHeight = options.outHeight;
        int outWidth = options.outWidth;

        int scale = Math.max(outHeight / 300, outWidth / 300);
        //scale向下取整,真实取值 2的n次幂
        options.inSampleSize = scale;

        options.inJustDecodeBounds = false;

        return BitmapFactory.decodeFile(filePath,options);
    }
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {

            case REQUEST_CODE_TAKE_PICTURE_SAVE:
                //如果拍照并保存 拍照App传递过来的Intent data空的,没有数据
                //图片进行显示
                //进行二次采样 
                Bitmap bitmap = sampleImage(mUri.getPath());
                showImage.setImageBitmap(bitmap);
                break;

        }

这样就实现了图片二次采样压缩,可以自己拿内存工具测测,不压缩之前大概为60M左右,压缩之后为4M左右,大大的降低了内存的占用,也是App的一项重要优化吧!

转载请注明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值