Android 图片压缩器
概述
Android 图片压缩器:一款高效的图片压缩器库,支持批量压缩,异步压缩、多线程多任务压缩,压缩比设置等特性。
详细
一、android图片压缩器特点
1.压缩比可以选择控制。
2.高效率的多线程压缩
3.支持批量压缩
二、实现过程
2.1 压缩任务线程类
该类是用于实现多线程压缩任务,利用CountDownLatch 计数计数实现多线程任务等待机制,核心代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /** * 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旋转,获取旋转角度等,核心代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /** * 获取旋转后的图片 * @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首先定义图片压缩状态监听接口,如下:
1 2 3 4 5 6 7 8 | /** * 图片压缩监听器 */ public interface ImageCompressListener { void onSuccess(List<String> outFilePathList); void onFailure(String message); } |
2.3.2 其次提供是否压缩判断方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 最后实现异步压缩功能,核心代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /** * 异步压缩多张图片 * @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 使用该压缩器很简单,直接一个方法搞定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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) { } }); |
四、源码目录截图
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?