1.壓縮比能夠選擇控制。html
2.高效率的多線程壓縮java
3.支持批量壓縮android
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 圖片圖像工具類ide
該工具類主要對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 壓縮器類的實現post
該功能類只要實現多線程文件壓縮功能,支持異步壓縮單張圖片和多張圖片等特性。線程
2.3.1首先定義圖片壓縮狀態監聽接口,以下:code
/** * 圖片壓縮監聽器 */ 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) { } });