序言
在开发中,我们常常会遇到构造图片,加载显示图片的情况。我们可以使用BitMapFactory的decode xxx 方法来构造BitMap对象。但现在普遍照片的质量,像素都很高,如果直接把照片拿来使用,加载到内存,就会很容易造成内存泄漏。也有浪费的嫌疑,比如我程序中只需要,200*200的图像,却是用2048x1536的图加载进去,这就不很浪费,很没有必要么,下面就将说明,如何对BitMap进行压缩处理,得到想要的尺寸的图片。
未处理的图片大小
我们想来看一下没有经过压缩处理的图片的大小。
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
//默认的图片格式是Bitmap.Config.ARGB_8888
Log.e(TAG, "onActivityResult: 图片的宽:" + bitmap.getWidth() + "--图片的高:"
+ bitmap.getHeight() + "--图片大小:" + bitmap.getWidth() * bitmap.getHeight() * 4 / 1024 / 1024 + "M");
这里默认是图片格式是ARGB_8888所以一个像素是占32位,8位等于1个字节,所以一个像素占4个字节内存。此时输出的log信息是:
E/MainActivity: onActivityResult: 图片的宽:1680--图片的高:1050--图片大小:6M
压缩处理成指定大小的图片
代码如下:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options);
Log.e(TAG, "onActivityResult: 压缩之前图片的宽:" + options.outWidth + "--压缩之前图片的高:"
+ options.outHeight + "--压缩之前图片大小:" + options.outWidth * options.outHeight * 4 / 1024 / 1024 + "M");
options.inSampleSize = calculateInSampleSize(options, 200, 200);
Log.e(TAG, "onActivityResult: inSampleSize:"+ options.inSampleSize);
options.inJustDecodeBounds = false;
Bitmap afterCompressBm = BitmapFactory.decodeFile(imagePath, options);
//默认的图片格式是Bitmap.Config.ARGB_8888
Log.e(TAG, "onActivityResult: 图片的宽:" + afterCompressBm.getWidth() + "--图片的高:"
+ afterCompressBm.getHeight() + "--图片大小:" + afterCompressBm.getWidth() * afterCompressBm.getHeight() * 4 / 1024 / 1024 + "M");
private 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;
}
log输出结果如下:
E/MainActivity: onActivityResult: 压缩之前图片的宽:1680--压缩之前图片的高:1050--压缩之前图片大小:6M
E/MainActivity: onActivityResult: inSampleSize:4
E/MainActivity: onActivityResult: 图片的宽:420--图片的高:263--图片大小:0M
我们看到图片的大小就变得很小了,这样就不会占很大的内存导致内存泄漏问题。这里我们可以着重看一下calculateInSampleSize这个方法的逻辑。内部代码逻辑不难,就是通过我们传入的想要的图片宽高值来计算inSampleSize的大小。这里我们通过log发现输出的inSampleSize值为4。此刻就表示,图片的宽变为原来的四分之一,高变为原来的四分之一。整张照片的像素就变为原来的16分之一。这样就达到了压缩的效果。
显示效果对比
压缩前,原图:
压缩后,图片:
补充
这里默认的图片格式是Bitmap.Config.ARGB_8888,我们也可以改变图片格式来对图片进行减小。这里补充下各种格式对应的字节大小:
- ARGB_8888 ->一个像素点占32位->4个字节
- RGB_565 ->一个像素点占16位->2个字节
- ARGB_4444 ->占16位->2个字节
- RGBA_F16 ->64位->8个字节
- ALPHA_8 ->不存储颜色信息,只存储透明度->一个像素占1个字节