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) { } });
四、源码目录截图