文章目录
前言
在Bitmap的内存管理中,介绍了Bitmap的压缩、缓存、复用等问题。其中的压缩方案是采样率压缩,这里再介绍几种其它的压缩方案,首先是原生的质量压缩,尺寸压缩,其次是哈夫曼压缩,也叫鲁班压缩或微信压缩。只有先知道原生压缩的原理,我们才能更好的优化改良,以及更好的理解哈夫曼压缩,而这种方案也是本文的分析重点。
1.基础知识
1.1色彩模式
ARGB:指的是一种色彩模式,里面A代表Alpha,R表示red, G表示green,B表示blue
自然界中所有的可见颜色都是由红、绿、蓝组成的,所以红、绿、蓝又称三原色,每个原色都存储着所表示颜色的信息值
A->alpht(透明度),R->red(红色),G->green(绿色),B-blue(蓝色)
1.2四种模式的区别
bitmap在内存中存在四种色彩的存储模式,它们的本质区别体现在每种模式下的bitmap的每个像素点,在内存中大小和组成成分的区别
1.3具体对比
- ALPHA_8: A ->8bit->一个字节,即8bit,一个像素总共占一个字节
- ARGB_8888: A->8bit->一个字节,R->8bit->一个字节,G->8bit->一个字节,B->8bit->一个字节,一个像素总共占用四个字节,8 + 8+ 8 + 8 = 32bit = 4byte
- ARGB_4444: A->4bit,R->4bit,G->4bit,B->4bit,一个像素总共占用两个字节,4 + 4 + 4 + 4 = 16bit = 2byte
- RGB_565: R->5bit,G->6bit,B->5bit,一个像素总共占用两个字节,5+ 6 + 5 = 16bit = 2byte
1.4bitmap内存占用大小计算方式
一张bitmap内存占用大小 = 像素点数 * 每个像素点内存占用大小 = width * height * 每个像素点占用内存大小
tips
- 我们知道了决定了bitmap内存占用的因素,只有改变这些因素才能改变bitmap的内存占用大小,Bitmap的压缩方案也是基于改变这些因素,来减小内存的占用
- bitmap的内存占用大小与在本地磁盘大小是不同的概念
1.5图片存在的形式
- 以File的形式存在于SD卡/磁盘中
- 以Stream的形式存在于内存中
- 以Bitmap的形式存在于内存中
1.6BitampFactory加载Bitmap对象的方式
- decodeFile 从文件中加载Bitmap对象
- decodeResource从资源中加载Bitmap对象
- decodeStream从输入流加载Bitmap对象
- decodeByteArray 从字节数组中加载Bitmap对象
2.压缩方案
2.1采样率压缩
/**
* 采样率压缩
* @param bitmap
* @param file
*/
public void compressInSampleSize(Bitmap bitmap, File file) {
BitmapFactory.Options options = new BitmapFactory.Options();
//正常的做法是通过ImageView的宽高,和图片自身的宽高计算采样率
//inJustDecodeBounds为true的时候不会真正的加载图片,只是解析图片原始宽高信息并不会去
//真正加载图片,轻量级操作
//options.inJustDecodeBounds = true;
//BitmapFactory.decodeFile(stringName, options);
//通过计算获取采样率inSampleSize
//options.inSampleSize = calculateInSampleSize(options, 150, 100);
//这里只是为了为了通过采用率压缩图片,不需要根据ImageView的宽高,和图片自身的宽高计算采样率
//直接赋值采样率为8,获得采样率后,再设置inJustDecodeBounds为false,真正的加载图片
//采样率数值越高,图片像素越低
int inSampleSize = 8;
options.inSampleSize = inSampleSize;
options.inJustDecodeBounds = false;
BitmapFactory.decodeFile(stringName, options);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 把压缩后的数据保存到baos中
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 不进行质量压缩
try {
if (file.exists()) {
file.delete();
} else {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取采样率
* @param options
* @param reqWidth 需要显示/控件定义的宽度
* @param reqHeight 需要显示/控件定义的高度
* @return
*/
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
int reqHeight) {
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
int halfWidth = width / 2;
int halfHeight = height / 2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize)
>= reqWidth) {
inSampleSize *=2;
}
}
return inSampleSize;
}
2.2尺寸压缩
/**
* 2. 尺寸压缩
* 通过减少单位尺寸的像素值,真正意义上的降低像素
* 通过缩放图片像素来达到减少图片占用内存大小的效果
* 使用场景: