bitmap大小以及压缩的常用三种方法

首先需要明确几个概念,如下
将bitmap转化为输出流

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

通过

Log.d("asdf", "baos==>" + baos.toByteArray().length);
Log.d("asdf", "bitmap==>" + bitmap.getByteCount());

得出

D/asdf: baos==>266390
D/asdf: bitmap==>14882400

这里的baos得出的数据266390,单位是字节(B),它是该图片实际的大小(就是占手机电脑上的存储空间),bitmap得出的数据14882400,单位是字节(B),则是该Bitmap在内存中的大小(他比baos的字节数大了好几个数量级,OOM内存溢出说的就是这货占地太大了!)。

那么他们是怎么计算出来的呢?就本例来说,试验用图片宽高为1080*3445,手机densityDpi = 480,图片格式默认采用ARGB_8888,即4位,根据公式:
(设备DPI / 图片所在文件夹所对应的dpi * 图片宽度 + 0.5f)*(设备DPI / 图片所在文件夹所对应的dpi * 图片高度 + 0.5f)*图片每个像素占用的字节数(ARGB_8888占4个)
(我是从本地文件加载的这张图片,设备DPI 和 图片所在文件夹所对应的dpi相同,所以直接得出 1080*3445*4=14882400)
通过文件管理器查看该图片的大小为 260KB 也就是baos字节数 266390 = 260 * 1024

图片格式如下表

图片格式 具体描述
ALPHA_8 只有一个alpha通道
ARGB_4444 这个从API 13开始不建议使用,因为质量太差
ARGB_8888 ARGB四个通道,每个通道8bit
RGB_565 每个像素占2Byte,其中红色占5bit,绿色占6bit,蓝色占5bit

那么关于压缩图片的3种常用方法

1.质量压缩

bitmap = BitmapFactory.decodeFileDescriptor(is.getFD(), null, null);// 从该图片的本地文件的输入流is得到其bitmap对象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 10, baos);   //留下10%,压缩90%
bitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());

特点:
使用compress()方法的options值进行压缩的方法是不会丢失像素总数的,也就是图片宽高都不会被改变,故而bitmap在内存中依然占据那么大地方,但图片存储大小变小了(毕竟不清晰了)。该方法只是通过修改图片的其它比如透明度等属性,使得图片大小变化而已,所以它就无法无限压缩,到达一个值之后就不会继续变小了。(实际的效果就是图片长宽并不会改变,改变的是清晰度之类神马的)

2.采样率压缩

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//压缩1/2
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm,null,options);

特点:
这里压缩1/2,指的是图片长宽分别压缩了1/2,bitmap在内存中占为原先的1/4,图片存储大小变化规律不明。实际的效果就是图片长宽真的变小了= =,存储大小也会变小(inSampleSize 只能为2的次方数)

3 .矩阵压缩

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//bitmap是一张图片
bitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.toByteArray().length);
/*该平方根表示大约缩进zoom倍,实际存储大小会接近32KB,可以自己算一下,就是长乘以宽*/
float zoom = (float) Math.sqrt(32 * 1024 / (float) baos.toByteArray().length);
Matrix matrix = new Matrix();
matrix.setScale(zoom, zoom);
resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
baos.reset();
resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
/*压缩到32KB为止*/
while (baos.toByteArray().length > 32 * 1024) {
    matrix.setScale(0.8f, 0.8f);
    resultBitmap = Bitmap.createBitmap(resultBitmap, 0, 0, resultBitmap.getWidth(), resultBitmap.getHeight(), matrix, true);
    baos.reset();
    resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
}

特点:上述代码中的矩阵压缩也是对图片的长宽做出拉伸,拉伸太多图片会模糊

你可能感兴趣的:(Android开发)