文章Android图片压缩总结中提到:
图片有以下存在形式:
1.文件形式(即以二进制形式存在于硬盘上)
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K
,那么通过流的形式读到内存中,也一定是占100K
的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 我试过500K
文件形式的图片加载到内存,以Bitmap
形式存在时,占用内存将近10M
,当然这个增大的倍数并不是固定的(原因在下面提到)。
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte
数
Bitmap: bitmap.getByteCount()
一、质量压缩
质量压缩的特点是: File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变
质量压缩主要借助Bitmap中的compress方法实现:
public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream)
这个方法用来将特定格式的压缩图片写入输出流(OutputStream
)中,当然例如输出流与文件联系在一起,压缩后的图片也就是一个文件。如果压缩成功则返回true,其中有三个参数:
1)format
是压缩后的图片的格式,可取值:Bitmap.CompressFormat .JPEG、~.PNG、~.WEBP
。
2)quality
的取值范围为[0,100]
,值越小,经过压缩后图片失真越严重,当然图片文件也会越小。(PNG
格式的图片会忽略这个值的设定)
3)stream指定压缩的图片输出的地方,比如某文件。
上述方法还有一个值得注意的地方是:当用BitmapFactory decode
文件时可能返回一个跟原图片不同位深的图片,或者丢失了每个像素的透明值(alpha)
,比如说,JPEG
格式的图片仅仅支持不透明的像素。文章 android
图片压缩在文末提到的下面这点可能就是这个原因:
当调用bitmap.compress(CompressFormat.JPEG, 100, fos)
;保存为图片时发现图片背景为黑色,如下图:
在这里插入图片描述
这时只需要改成用png保存就可以了,bitmap.compress(CompressFormat.PNG, 100, fos)
;,如下图:
public static void compressBmpToFile(Bitmap bmp,File file){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 80;//个人喜欢从80开始,
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 10;
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
这段代码来自 Android图片压缩总结,我根据自己的需求改了改,但是大同小异,所以就直接贴了。
随着代码中的option
逐渐变小,我们可以在logcat
中打印baos
的大小来查看图片的大小。我们也可以去掉while
的循环条件,一直压缩下去看效果,最终一张照片可能就由原来的3、4M
变成了几百K
甚至几百B
了。我在试的过程中将option
设置成100
,压缩后偶尔会出现一张3、4M
的图片经过压缩后竟变成了6、7M
,这里还是有点困惑,不知道为什么。
随后,我想把这个压缩后的图片(1、200KB
)填充到ImageView
中时却失败了,logcat
中提示图片过大!这就是文章开头提到的问题,虽然我们通过质量压缩使File
形式的图片文件缩小了,但是并没有改变图片的宽高,原先是1080*1920
分辨率的图片经压缩后还是1080*1920
,而File格式转换成Bitmap
格式进入到内存中时,内存是根据图片的像素数量来给图片分配内存大小的,还是有好几M
,因此填充ImageView
失败。
顺便提一下,可以用 bitmap.getByteCount()
获取存储bitmap像素的内存大小,但是KITKAT
(Android 4.4版本)以后用getAllocateByteCount()
获取。一般情况下,后者返回值比前者大,比如,当bitmap被重用去decode
另外更小的bitmaps
时,或者被人为地配置一下属性值,比如setWidth()、setHeight()、reconfigure()
时,如果bitmap
不做以上操作,二者的返回值应该是一样的。(译文,不太懂)
二、尺寸压缩
特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩
我们主要通过BitmapFactory
中的decodeFile
方法对图片进行尺寸压缩:
public static Bitmap decodeFile (String pathName, BitmapFactory.Options opts)
其中有两个参数:
1)pathName
是图片文件的路径。
2)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 已弃用。(这是译文,不太理解!!!)
下面是一段实现的代码
private Bitmap sizeCompres(String path, int rqsW, int rqsH) {
// 用option设置返回的bitmap对象的一些属性参数
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;// 设置仅读取Bitmap的宽高而不读取内容
BitmapFactory.decodeFile(path, options);// 获取到图片的宽高,放在option里边
final int height = options.outHeight;//图片的高度放在option里的outHeight属性中
final int width = options.outWidth;
int inSampleSize = 1;
if (rqsW == 0 || rqsH == 0) {
options.inSampleSize = 1;
} else if (height > rqsH || width > rqsW) {
final int heightRatio = Math.round((float) height / (float) rqsH);
final int widthRatio = Math.round((float) width / (float) rqsW);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
options.inSampleSize = inSampleSize;
}
return BitmapFactory.decodeFile(path, options);// 主要通过option里的inSampleSize对原图片进行按比例压缩
}
参考文章:
上面就是简单的质量压缩与尺寸压缩。
http://blog.csdn.net/cherry609195946/article/details/9264409?8317
http://blog.csdn.net/jdsjlzx/article/details/44228935