Android 图片压缩器

概述

Android 图片压缩器:一款高效的图片压缩器库,支持批量压缩,异步压缩、多线程多任务压缩,压缩比设置等特性。

详细

一、android图片压缩器特点

1.压缩比可以选择控制。

2.高效率的多线程压缩

3.支持批量压缩

二、实现过程

2.1 压缩任务线程类

该类是用于实现多线程压缩任务,利用CountDownLatch 计数计数实现多线程任务等待机制,核心代码如下:

/**
 * Created by caizhiming on 2016/6/2.
 * 图片压缩任务线程
 */
public class CompressTask extends Thread{
    CountDownLatch mLatch;
    Boolean mRet;
    String mInFilePath;
    String mOutFilePath;
    boolean mIsNeedCompress;
    public CompressTask(CountDownLatch latch,Boolean ret,String inFilePath,String outFilePath,boolean isNeedCompress){
        mLatch = latch;
        mRet = ret;
        mInFilePath = inFilePath;
        mOutFilePath = outFilePath;
        mIsNeedCompress = isNeedCompress;
    }
    @Override
    public void run() {
        if(mIsNeedCompress) {
            mRet = NativeBitmapUtil.syncCompressBitmap(mInFilePath,mOutFilePath);
            mLatch.countDown();
        }else{
            mRet = true;
            mLatch.countDown();
        }
    }
}

2.2 图片图像工具类

该工具类主要对Bitmap图像处理做了一些封装,比如Bitmap旋转,获取旋转角度等,核心代码如下:

/**
 * 获取旋转后的图片
 * @param path
 * @return
 */
public static Bitmap getRotateBitmapByPath(String path) {
    return rotateBitmapByDegree(BitmapFactory.decodeFile(path), getBitmapDegree(path));
}
/**
 * 获取旋转后的图片
 * @param path
 * @return
 */
public static Bitmap getRotateBitmapByPath(String path,final int maxSize) {
    BitmapFactory.Options  options= new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);
    options.inSampleSize = BitmapUtils.calculateInSampleSize(options,maxSize,maxSize);
    options.inJustDecodeBounds = false;
    return rotateBitmapByDegree(BitmapFactory.decodeFile(path,options), getBitmapDegree(path));
}
/**
 * 将图片按照某个角度进行旋转
 *
 * @param bm
 *            需要旋转的图片
 * @param degree
 *            旋转角度
 * @return 旋转后的图片
 */
public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
    Bitmap returnBm = null;

    // 根据旋转角度,生成旋转矩阵
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    try {
        if (bm != null) {
            // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
        }
    } catch (OutOfMemoryError e) {
    }
    if (returnBm == null) {
        returnBm = bm;
    }
    if (bm != returnBm) {
        bm.recycle();
    }
    return returnBm;
}
/**
 * 读取图片的旋转的角度
 *
 * @param path
 *            图片绝对路径
 * @return 图片的旋转角度
 */
public static int getBitmapDegree(String path) {
    int degree = 0;
    try {
        // 从指定路径下读取图片,并获取其EXIF信息
        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;
}

2.3 压缩器类的实现

该功能类只要实现多线程文件压缩功能,支持异步压缩单张图片和多张图片等特性。

2.3.1首先定义图片压缩状态监听接口,如下:

/**
 * 图片压缩监听器
 */
public interface ImageCompressListener {
    void onSuccess(List<String> outFilePathList);

    void onFailure(String message);
}

2.3.2 其次提供是否压缩判断方案:

public static long MAX_FILE_SIZE = 1024 * 1024;
/**
 * 是否压缩图片:大于 1280*1280的 图片 需要压缩 或者 大小大于1M
 * @param inFilePath
 * @return isNeedCompress
 */
public static boolean isNeedCompress(String inFilePath){
    boolean ret = true;
    File file = new File(inFilePath);
    if(file != null && file.exists()){
        BitmapFactory.Options  options= new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(inFilePath,options);
        if(options.outWidth <= BitmapUtil.MAX_SIZE
                && options.outHeight <= BitmapUtil.MAX_SIZE){
            ret = false;
        }
        if(file.length() > MAX_FILE_SIZE){
            ret = true;
        }
    }
    return ret;
}

2.3.3 最后实现异步压缩功能,核心代码如下:

/**
 * 异步压缩多张图片
 * @param inFilePathList:需要压缩的图片的路径列表
 * @param outList:压缩后输出的新图片的路径列表
 * @param listener:压缩监听器
 */
public static void compress(final List<String> inFilePathList, final List<String> outList
        , final ImageCompressListener listener) {
    final List<String> outFilePathList = (outList == null) ? createOutFilePathList(inFilePathList) : outList;
    new AsyncTask<Void, Void, Boolean>() {
        @Override
        protected Boolean doInBackground(Void... params) {
            boolean isSuccess = true;
            CountDownLatch singal = new CountDownLatch(inFilePathList.size());
            List<Boolean> retList = new ArrayList<>();
            for (int i = 0; i < inFilePathList.size(); i++) {
                retList.add(i, Boolean.TRUE);
                boolean isNeedCompress = isNeedCompress(inFilePathList.get(i));
                if(!isNeedCompress){
                    outFilePathList.set(i,inFilePathList.get(i));
                }
                CompressTask compressTask = new CompressTask(singal, retList.get(i)
                        , inFilePathList.get(i), outFilePathList.get(i),isNeedCompress);
                compressTask.start();
            }
            try {
                singal.await();
                for (Boolean ret : retList) {
                    if(!ret) isSuccess = false;
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
                isSuccess = false;
            }finally {
                if(!isSuccess) {
                    String failErrorMsg = "";
                    for(int i =0;i < retList.size();i++){
                        if(!retList.get(i)){
                            failErrorMsg += "\nCompress error: "+inFilePathList.get(i);
                        }
                    }
                }
                return isSuccess;
            }
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            if(listener != null){
                if(result) {
                    listener.onSuccess(outFilePathList);
                    for(String path :outFilePathList){
                        Log.v("czm","outFilePath="+path);
                    }
                }else{
                    listener.onFailure("图片压缩失败!!");
                }
            }
        }
    }.execute();
}
三、使用方法

3.1 使用该压缩器很简单,直接一个方法搞定:

    List<String> srcFilePathList = new ArrayList<>();
    List<String> outputFilePathList = new ArrayList<>();
    //默认压缩方法
    XCImageCompressor.compress(srcFilePathList, new XCImageCompressor.ImageCompressListener() {
        @Override
        public void onSuccess(List<String> outFilePathList) {

        }

        @Override
        public void onFailure(String message) {

        }
    });
    
    //支持压缩后的输出目录的压缩方法
    XCImageCompressor.compress(srcFilePathList, outputFilePathList,new XCImageCompressor.ImageCompressListener() {
        @Override
        public void onSuccess(List<String> outFilePathList) {

        }

        @Override
        public void onFailure(String message) {

        }
    });
四、源码目录截图

111.png


注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Luban(鲁班)——Android图片压缩工具,仿微信朋友圈压缩策略。项目描述目前做app开发总绕不开图片这个元素。但是随着手机拍照分辨率的提升,图片的压缩成为一个很重要的问题。单纯对图片进行裁切,压缩已经有很多文章介绍。但是裁切成多少,压缩成多少却很难控制好,裁切过头图片太小,质量压缩过头则显示效果太差。于是自然想到app巨头“微信”会是怎么处理,Luban(鲁班)就是通过在微信朋友圈发送近100张不同分辨率图片,对比原图与微信压缩后的图片逆向推算出来的压缩算法。因为有其他语言也想要实现 Luban,所以描述了一遍算法步骤 因为是逆向推算,效果还没法跟微信一模一样,但是已经很接近微信朋友圈压缩后的效果,具体看以下对比!效果与对比内容原图LubanWechat截屏 720P720*1280,390k720*1280,87k720*1280,56k截屏 1080P1080*1920,2.21M1080*1920,104k1080*1920,112k拍照 13M(4:3)3096*4128,3.12M1548*2064,141k1548*2064,147k拍照 9.6M(16:9)4128*2322,4.64M1032*581,97k1032*581,74k滚动截屏1080*6433,1.56M1080*6433,351k1080*6433,482k导入compile 'io.reactivex:rxandroid:1.2.1' compile 'io.reactivex:rxjava:1.1.6' compile 'top.zibin:Luban:1.0.5'使用Listener方式Luban内部采用io线程进行图片压缩,外部调用只需设置好结果监听即可Luban.get(this)     .load(File)                     //传人要压缩的图片     .putGear(Luban.THIRD_GEAR)      //设定压缩档次,默认三挡     .setCompressListener(new OnCompressListener() { //设置回调         @Override         public void onStart() {             //TODO 压缩开始前调用,可以在方法内启动 loading UI         }         @Override         public void onSuccess(File file) {             //TODO 压缩成功后调用,返回压缩后的图片文件         }         @Override         public void onError(Throwable e) {             //TODO 当压缩过去出现问题时调用         }     }).launch();    //启动压缩RxJava方式RxJava 调用方式请自行随意控制线程Luban.get(this)         .load(file)         .putGear(Luban.THIRD_GEAR)         .asObservable()         .subscribeOn(Schedulers.io())         .observeOn(AndroidSchedulers.mainThread())         .doOnError(new Action1() {             @Override             public void call(Throwable throwable) {                 throwable.printStackTrace();             }         })         .onErrorResumeNext(new Func1>() {             @Override             public Observable<? extends File> call(Throwable throwable) {                 return Observable.empty();             }         })         .subscribe(new Action1() {             @Override             public void call(File file) {                 //TODO 压缩成功后调用,返回压缩后的图片文件             }         }); 标签:Luban(鲁班)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值