Android 的图片压缩

本文详细介绍了Android中图片压缩的三种方法:质量压缩、尺寸压缩和使用Luban库进行压缩。重点讲解了Luban库的压缩效果和源码分析,指出其在多图片压缩时可能出现的内存溢出问题以及对RxJava的依赖问题。

我用的图片主要分为3种       1、质量压缩 ,2、尺寸压缩,3、Luban压缩(鲁班)

一、质量压缩

   质量压缩的特点是:  File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变           

  质量压缩主要借助Bitmap中的compress方法实现:

public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream)

 

这个方法用来将特定格式的压缩图片写入输出流(OutputStream)中,当然例如输出流与文件联系在一起,压缩后的图片也就是一个文件。如果压缩成功则返回true,其中有三个参数:

  • format是压缩后的图片的格式,可取值:Bitmap.CompressFormat .JPEG、~.PNG、~.WEBP。
  • quality的取值范围为[0,100],值越小,经过压缩后图片失真越严重,当然图片文件也会越小。(PNG格式的图片会忽略这个值的设定)
  • stream指定压缩的图片输出的地方,比如某文件。

下面是质量压缩的代码:

  1. public static void compressBmpToFile(Bitmap bmp,File file){  
  2.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  3.         int options = 80;//个人喜欢从80开始,  
  4.         bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);  
  5.         while (baos.toByteArray().length / 1024 > 100) {   
  6.             baos.reset();  
  7.             options -= 10;  
  8.             bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);  
  9.         }  
  10.         try {  
  11.             FileOutputStream fos = new FileOutputStream(file);  
  12.             fos.write(baos.toByteArray());  
  13.             fos.flush();  
  14.             fos.close();  
  15.         } catch (Exception e) {  
  16.             e.printStackTrace();  
  17.         }  
  18.     }  

二、尺寸压缩

特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩

我们主要通过BitmapFactory中的decodeFile方法对图片进行尺寸压缩:

public static Bitmap decodeFile (String pathName, BitmapFactory.Options opts)

 

其中有两个参数:

  • pathName是图片文件的路径。
  • opts 就是所谓的采样率,它里边有很多属性可以设置,我们通过设置属性来达到根据自己的需要,压缩出指定的图片。其中比较常用的属性有:

boolean inJustDecodeBounds —— 如果设置为true,则只读取bitmap的宽高,而忽略内容。

int inSampleSize—— 如果>1,调用decodeFile方法后,就会得到一个更小的bitmap对象(已压缩)。比如设置为2,那么新Bitmap的宽高都会是原Bitmap宽高的1/2,总体大小自然就是原来的1/4了,以此类推。

boolean inPurgeable—— 如果设置为true,压缩后的图片像素占的内存将会在系统清理内存的时候被回收掉,当像素的信息再次被用到时将会自动重新decode该像素(比如getPixels()时)。(慎用!重复decode可以会造成UI的卡顿,API level 21 已弃用)

boolean inInputShareable—— 与inPurgeable配合使用,如果inPurgeable设置成false,自动忽略此值,如果inPurgeable为true,此值决定是否该bitmap能分享引用给输入数据(inputstream,array等),或者必须进行深拷贝。API level 21 已弃用。(这是译文,不太理解!!!)

 

下面是一段实现的代码

 
  1. private Bitmap sizeCompres(String path, int rqsW, int rqsH) {

  2. // 用option设置返回的bitmap对象的一些属性参数

  3. final BitmapFactory.Options options = new BitmapFactory.Options();

  4. options.inJustDecodeBounds = true;// 设置仅读取Bitmap的宽高而不读取内容

  5. BitmapFactory.decodeFile(path, options);// 获取到图片的宽高,放在option里边

  6. final int height = options.outHeight;//图片的高度放在option里的outHeight属性中

  7. final int width = options.outWidth;

  8. int inSampleSize = 1;

  9. if (rqsW == 0 || rqsH == 0) {

  10. options.inSampleSize = 1;

  11. } else if (height > rqsH || width > rqsW) {

  12. final int heightRatio = Math.round((float) height / (float) rqsH);

  13. final int widthRatio = Math.round((float) width / (float) rqsW);

  14. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

  15. options.inSampleSize = inSampleSize;

  16. }

  17. return BitmapFactory.decodeFile(path, options);// 主要通过option里的inSampleSize对原图片进行按比例压缩

  18. }

三、Luban压缩

这里介绍下一个第三方开源库——Luabn(最接近微信朋友圈压缩图片算法)

2.使用Luban压缩图片效果

  

上面两图中的上部分图片是原图,下面部分是经过Luban压缩过后的图片

效果:

第一张原图4.55m 尺寸3456x4608。 压缩过后53k 尺寸1152x1536

第二张原图1.16m 尺寸1080x1920。 压缩过后150k 尺寸360x640

我们可以发现压缩后的图片在不放大的情况下,图片效果和原图一致,Luban的处理效果特别好。

如何使用Luban压缩图片

1.在项目中的build.gradle添加依赖(需要用到RxJava1.0) 
这里写图片描述

2.在代码中使用Luban压缩方法

1)Listerner方式。传入图片File,调用设置压缩监听setCompressListerner方法,处理压缩结果。 
这里写图片描述

2)Rxjava方式,传入图片File,调用asObservable方法返回一个Observable观察者对象,使用RxJava方式来处理压缩结果。 
这里写图片描述

3.Luban源码分析

源码中最主要的方法就是thirdCompress(File file),即如何计算得出理想的压缩后宽高,以及图片大小。

Luban存在的不足

1.不能很好的支持多图片压缩。(出现问题:多图压缩出现OOM)

2.项目使用中必须添加RxJava依赖。(已在测试项目中剔除掉RxJava依赖 「链接」

 

 

 

<think> 首先,用户查询是关于Android系统下的图片压缩方法。基于提供的引用,我需要构建一个清晰、结构化的回答。 关键点来自引用: - 引用[1] 提到Android使用Skia引擎,移除了哈夫曼算法以节省CPU,但解码保留了它。建议绕过Bitmap API使用哈夫曼算法进行压缩。 - 引用[2] 描述了质量压缩法,使用Bitmap.compress方法指定压缩比例。 - 引用[3] 谈到按比例缩放图片,可能结合质量缩放以避免失真。 - 引用[4] 解释了使用BitmapFactory.Options进行尺寸压缩,通过inSampleSize缩放图片大小。 用户要求生成相关问题,所以我需要在回答中包含相关问题部分。 系统级指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式,单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 引用的段落末尾添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,保证真实可靠。 用户可见层要求: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 组织回答结构: 1. **介绍**:简要解释Android图片压缩的必要性和常见方法。 2. **主要方法**: - **质量压缩法**:基于引用[2],描述使用Bitmap.compress方法压缩图片质量。 - **尺寸压缩法**:基于引用[4],描述使用BitmapFactory.Options和inSampleSize进行尺寸缩放。 - **绕过Bitmap API使用哈夫曼算法**:基于引用[1],解释如何自定义编码以避免失真。 - **结合方法**:基于引用[3],建议结合比例缩放和质量缩放以避免失真。 3. **代码示例**:提供简单代码示例,参考引用中的代码片段。 4. **注意事项**:讨论优缺点,如失真问题、CPU使用等。 5. **相关问题**:生成相关问题部分。 确保使用中文回答。 添加引用标识: - 在相关内容后添加[^1]、[^2]等。 生成相关问题: - 基于主题,生成3-4个相关问题。 数学表达式:在这个上下文中,可能不需要数学表达式,但如果涉及计算,如比例缩放,可以使用行内数学,例如缩放比例$1/2$。 现在,草拟回答: - **介绍**:Android系统提供多种图片压缩方法以减少图片大小,但需注意失真问题。 - **方法1:质量压缩法**:使用Bitmap.compress方法,指定压缩比例(如50%),减少文件大小但可能失真[^2]。 - **方法2:尺寸压缩法**:使用BitmapFactory.Options,设置inSampleSize缩放比例(如2表示缩小一半),减少像素大小[^4]。 - **方法3:自定义哈夫曼算法**:绕过Bitmap API,实现哈夫曼编码以优化压缩和解码[^1]。 - **最佳实践**:建议先进行尺寸压缩,再根据需要进行质量压缩,避免过度失真[^3]。 - **代码示例**:提供简单代码。 - **相关问题**:生成相关问题。 相关问题想法: 1. 如何在Android中避免图片压缩后的失真问题? 2. 质量压缩和尺寸压缩的优缺点比较是什么? 3. 如何实现自定义的哈夫曼算法压缩图片? 4. Android图片压缩的性能优化技巧有哪些? 确保回答真实可靠:基于提供的引用,不添加虚假信息。 </think>### Android图片压缩方法详解 在Android开发中,图片压缩是优化应用性能的关键技术之一,能减少内存占用、提升加载速度,并节省存储空间。Android系统提供了原生API和自定义方法来实现压缩,但需注意失真问题。以下我将基于真实可靠的开发实践,逐步介绍主要压缩方法、代码实现及注意事项。内容参考了Android官方文档和常见开发经验[^1][^2][^3][^4]。 #### 1. **质量压缩法** 质量压缩法通过降低图片的编码质量来减少文件大小,不改变像素尺寸。适用于需要保留原图尺寸的场景(如分享图片),但过度压缩可能导致失真。 - **原理**:使用`Bitmap.compress()`方法,指定压缩格式(如JPEG)和质量比例(0-100%)。质量越低,文件越小,但失真风险越高。 - **代码示例**:以下函数演示如何将图片压缩到指定质量比例并保存。 ```java /** * 质量压缩法:指定压缩比例(默认50%) * @param image 原始图片 * @param filepath 保存路径 * @param quality 压缩质量比(0-100) * @return 压缩后的Bitmap(原图尺寸不变) */ public static Bitmap compressQuality(Bitmap image, String filepath, int quality) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, quality, baos); // 压缩数据写入流 FileOutputStream fos = new FileOutputStream(filepath); fos.write(baos.toByteArray()); // 写入文件 fos.flush(); fos.close(); return image; // Bitmap未变,文件大小减小 } catch (IOException e) { e.printStackTrace(); return null; } } ``` - **说明**:设置`quality=50`时,文件大小通常减小到原图的1/4(例如100KB降至25KB)[^2]。 - **优缺点**:简单高效,但高压缩率可能导致模糊或锯齿。 #### 2. **尺寸压缩法** 尺寸压缩法通过减少像素数量来缩小图片尺寸,适合缩略图或列表项显示。此方法能显著降低内存占用,但直接改变图片分辨率。 - **原理**:使用`BitmapFactory.Options`设置`inSampleSize`(缩放比例),例如设为2表示宽高各缩小一半,文件大小缩小到1/4(比例计算为$1/\text{inSampleSize}^2$)。 - **代码示例**:先解码边界信息计算缩放比例,再加载压缩图。 ```java /** * 尺寸压缩法:按比例缩放图片 * @param filePath 图片路径 * @param targetWidth 目标宽度 * @param targetHeight 目标高度 * @return 压缩后的Bitmap */ public static Bitmap compressSize(String filePath, int targetWidth, int targetHeight) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 只解码边界信息,不分配像素内存 BitmapFactory.decodeFile(filePath, options); // 计算缩放比例 int inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight); options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; // 设置缩放值 return BitmapFactory.decodeFile(filePath, options); // 返回压缩图 } private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // 计算最大缩放比,保持比例 while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; // 返回2的幂次值(如2,4,8) } ``` - **说明**:`inJustDecodeBounds=true`避免内存分配,仅获取图片原始尺寸[^4]。缩放后,图片像素减少,文件大小大幅下降。 - **优缺点**:高效节省内存,但可能因分辨率降低导致细节丢失。 #### 3. **自定义哈夫曼算法压缩** Android的Skia引擎默认移除了哈夫曼编码(以节省CPU),但解码时支持它。自定义实现可绕过Bitmap API,减少失真。 - **原理**:哈夫曼算法通过变长编码优化压缩率,尤其在JPEG处理中。Android默认使用定长编码(性能高但压缩率低),自定义可启用哈夫曼。 - **实现建议**: - 使用第三方库(如libjpeg-turbo)集成哈夫曼编码。 - 示例步骤:解码图片→应用哈夫曼算法重新编码→保存。 - **优缺点**:压缩率更高,失真较小,但CPU消耗较大,需在后台线程执行[^1]。 #### 4. **组合方法与最佳实践** - **推荐流程**:先尺寸压缩(减少像素量),再质量压缩(微调文件大小),以平衡性能和失真[^3]。 - **注意事项**: - **失真控制**:避免单独使用高比例质量压缩;尺寸压缩时保持宽高比。 - **性能优化**:在主线程外执行压缩(AsyncTask或协程),防止卡顿。 - **格式选择**:JPEG适合照片(有损压缩),PNG适合图标(无损但文件大)。 - **大小限制**:压缩后检查文件大小,若超出预期,可迭代调整参数。 - **真实场景**:社交应用上传图片时,先用尺寸压缩到800x600,再质量压缩到70%。 通过以上方法,您可以根据需求选择合适策略。如有更多细节需求,请提供具体场景(如目标文件大小或图片类型)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值