[小白装逼]Android图像处理(压缩+裁剪+图片选择)内附DEMO

在安卓的开发中肯定避免不了对图像的处理,图像的处理最大的问题就是会出现OOM,为了找到一个更好效率更高的图形处理框架,本小白试了几个开源框架,最后剩下这些个人认为比较好用的~~~

导入

这里需要对文件的读写权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 //异步,compress需要用到
    compile 'io.reactivex:rxandroid:1.1.0'
    //图片剪裁
    compile 'com.yalantis:ucrop:2.2.0'
    //图片选择
    compile 'com.foamtrace:photopicker:1.0'
    //glide图片处理
    compile 'com.github.bumptech.glide:glide:3.5.2'
    //compress压缩
    compile 'id.zelory:compressor:1.0.3'
    //luban压缩
    compile 'top.zibin:Luban:1.0.9'

图片选择

我这里的图片选择使用了photopicker,可选择1张-9张,当然选择那里的布局可以自定义theme,在manifest里设置就可以了
manifest中的设置

 
        <activity
            android:name="com.foamtrace.photopicker.PhotoPickerActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:theme="@style/PhotoPickerTheme" />
        <activity
            android:name="com.foamtrace.photopicker.PhotoPreviewActivity"
            android:screenOrientation="portrait"
            android:theme="@style/PhotoPickerTheme" />

在平时的项目中,为了使照片选择可以适用多个项目,我把他做成了DialogFragment,这样,在其他项目只要继承对应接口就可以实现这个功能了
主要实现功能的代码如下(设置选择的属性后打开Activity),选择后会调用onACtivityResult

PhotoPickerIntent intent = new PhotoPickerIntent(getActivity());
            intent.setSelectModel(SelectModel.MULTI);
            intent.setShowCarema(false); // 是否显示拍照, 默认false
            intent.setMaxTotal(type); // 最多选择照片数量,默认为9
            intent.setSelectedPaths(imagePaths); // 已选中的照片地址, 用于回显选中状态
startActivityForResult(intent, RESULT_LOAD_IMAGE);//打开Activity选择照片

在DEMO中的拍照功能是直接调用了系统原生的拍照功能

public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.i("----requestCode----",requestCode+";;"+ UCrop.REQUEST_CROP+";;"+ UCrop.RESULT_ERROR);
        if (resultCode == RESULT_OK ) {
            if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA || requestCode == RESULT_LOAD_IMAGE) {
                //拍照

                if (requestCode == REQUEST_CODE_CAPTURE_CAMEIA) {

                    Uri uri = data.getData();
                    if (uri == null) {
                        Bundle bundle = data.getExtras();
                        Bitmap bitmap = (Bitmap) bundle.get("data");
                        String path = Environment.getExternalStorageDirectory().getPath() + "/gz/";
                        try {
                            File dirFile = new File(path);
                            if (!dirFile.exists()) {
                                dirFile.mkdir();
                            }
                            File myCaptureFile = new File(path +new Date().getTime()+ "photo.jpeg");
                            if (!myCaptureFile.exists()){
                                myCaptureFile.createNewFile();
                            }
                            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
                            bos.flush();
                            bos.close();
                            uri = Uri.fromFile(myCaptureFile);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    Log.i("---DFragmentTakePho---", uri.toString());
                    uriList.add(uri);
                    ((MyDialogListContract) getActivity()).returnUri(uriList,getTag());

                } else
                    //从相册筛选
                    if (requestCode == RESULT_LOAD_IMAGE) {
                        if (data != null) {
                            imagePaths = data.getStringArrayListExtra(PhotoPickerActivity.EXTRA_RESULT);
                            for (String uri : imagePaths) {
                                uriList.add(Uri.fromFile(new File(uri)));
                            }
                            Log.i("---DFragmentChoose---", imagePaths.toString());
                            ((MyDialogListContract) getActivity()).returnUri(uriList,getTag());
                        }else{
                            Log.e("---dialogChoose---","dataNULL");
                        }
                    }
                dismiss();//选择好照片就更关闭dialog
            }

        }
    }

压缩

对于压缩,个人认为最好的方案是使用jni的压缩,而在这里使用了两个压缩框架compressor和Luban

Compressor

这里使用rxjava异步的方式来进行压缩

Compressor
                    .getDefault(this)//使用默认的设置
                    .compressToFileAsObservable(file)//需要压缩的文件
                    .subscribeOn(Schedulers.io())//压缩时在非主线程中执行
                    .observeOn(AndroidSchedulers.mainThread())//执行完成后的异步在主线程中执行
                    .subscribe(new Action1() {//压缩成功是调用
                        @Override
                        public void call(File file) {
                            Glide.with(CompressActivity.this).load(file).into(img_compress);
                            Log.i("---Compresslength---",getFileSize(file)+"kb");
                            tv_compress.setText((int)getFileSize(file)+"kb");
                        }
                    }, new Action1() {//压缩时出错调用
                        @Override
                        public void call(Throwable throwable) {
                            Log.e("---Compressor---",throwable.getMessage());
                        }
                    });

Luban

Luban的也支持rxjava的异步,这里使用了其提供的默认方式

 Luban.get(this).load(file)//设置要压缩的文件
                    .putGear(Luban.THIRD_GEAR)//压缩的档次
                    .setCompressListener(new OnCompressListener() {//压缩回调
                        @Override
                        public void onStart() {//压缩开始

                        }

                        @Override
                        public void onSuccess(File file) {//压缩成功
                            Glide.with(CompressActivity.this).load(file).into(img_luban);
                            Log.i("---Lubanlength---",getFileSize(file)+"kb");
                            tv_luban.setText((int)getFileSize(file)+"kb");
                        }

                        @Override
                        public void onError(Throwable e) {//压缩失败
                            Log.e("---Luban---",e.getMessage());
                        }
                    }).launch();//开始压缩

这两个压缩框架,Luban的效果会更好,压缩效率更接近微信朋友圈图片的压缩,但是在之前的版本,Luban压缩后的图片文件会没有后缀名(这个很坑),当然在1.0.9开始就修复了这个问题,不过之前在项目中使用了Luban压缩出现了奇怪的现象(具体忘了),后来就换成使用Compressor了.
个人认为,Luban在之后的版本应该能做的更好,优化的更好,但是目前的我还是使用Compressor先了

裁剪

裁剪方面,这里选择了UCROP,个人感觉效果挺不错的
manifest设置


        <activity
            android:name="com.yalantis.ucrop.UCropActivity"
            android:screenOrientation="portrait"/>

主要代码(UCROP的布局颜色设置在此处设置,并不是在manifest中设置,裁剪后回调用onActivityResult)

 /**
     * 剪裁图片
     * @param photoUri
     */
    public void setCrop(Uri photoUri){
        UCrop uCrop = UCrop.of(photoUri, uri);
        uCrop.withAspectRatio(1,1);//裁剪比例
        UCrop.Options options = new UCrop.Options();
        options.setToolbarColor(Color.parseColor("#008CEE"));//状态栏颜色
        options.setStatusBarColor(Color.parseColor("#008CEE"));//通知栏颜色
        //开始设置
        //一共三个参数,分别对应裁剪功能页面的“缩放”,“旋转”,“裁剪”界面,对应的传入NONE,就表示关闭了其手势操作,比如这里我关闭了缩放和旋转界面的手势,只留了裁剪页面的手势操作
        options.setAllowedGestures(UCropActivity.NONE, UCropActivity.ALL, UCropActivity.ALL);
        //设置是否展示矩形裁剪框
        options.setShowCropFrame(true);
        //结束设置
        uCrop.withOptions(options);
        uCrop.start(this);
    }
    /**
     * 剪裁后会返回触发这里
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == UCrop.REQUEST_CROP) {
            Uri resultUri;
            try {
                resultUri = UCrop.getOutput(data);//获取剪裁的结果,在剪裁时点击返回时会再此触发Null...
            }catch (NullPointerException e){
                return;
            }
            Glide.with(this).load(resultUri).into(img);
        }else
        if (resultCode == UCrop.RESULT_ERROR) {//剪裁出错
            Log.e("---cropERR---", data.toString());
        }
    }

结尾吐槽

以上是本人在项目中接触到的安卓图像处理框架,当时一直纠结着使用哪个比较好,后来都试了下,觉得这些还是挺好用的,除此之外,还有Glide加载图片也是棒棒的,在DEMO中也有使用

DEMO:https://github.com/lewis-v/PhotoTest.git

以上内容,纯属个人理解,如有错误,请指出纠正,若有雷同,你肯定在做梦~~~~

你可能感兴趣的:(android学习笔记)