图片常见问题处理
-
图片占用的内存计算
图片宽度 * 图片高度 * 单位像素占用的字节
单位像素占用的字节和Bitmap.Config有关,常用的有RGB_565和ARGB_8888。RGB_565占2个字节,ARGB_8888占4个字节支持透明度,RGB_565表示的颜色值没有ARGB_8888的多,RGB_565不支持透明度。
-
如何处理图片占用内存过大导致内存溢出
通过图片占用内存的计算公式可以得知,有两个方法减小图片占用的内存:
- 设置Bitmap.Config为RGB_565,这样图片占用的内存为ARGB_8888的一半。
BitmapFactory.Options option = new BitmapFactory.Options();
option.inPreferredConfig = Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeFile(imgPath, option);
- 减小图片的高度和宽度
BitmapFactory.Options option = new BitmapFactory.Options();
//值为0.5代表高度和宽度缩小一半,值为1表示不变
option.inSampleSize = 0.5;
Bitmap bitmap = BitmapFactory.decodeFile(imgPath, option);
-
实际应用
- 实际开发中,我们一般不知道待加载的图片的高度和宽度,如果想让内存中图片的高度和宽度低于200px从而减少图片占用的内存,我们如何设置inSampleSize的值呢?BitmapFactory.Options提供了inJustDecodeBounds参数。当需要获取Bitmap的宽度和高度的时候,把inJustDecodeBounds设置为true,Bitmap创建好后,是不占用内存的,这样可以获取到高度和宽度;当需要获取可以显示的Bitmap时候,再把inJustDecodeBounds设置为false。下面是我项目中封装的方法:
public static Bitmap ratio(String imgPath, float width, float height) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 开始读入图片,此时把options.inJustDecodeBounds 设回true,即只读边不读内容
newOpts.inJustDecodeBounds = true;
newOpts.inPreferredConfig = Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 想要缩放的目标尺寸
float hh = height;
float ww = width;
// 计算缩放比例
int be = 1;// be=1表示不缩放
if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;// 设置缩放比例
// 开始压缩图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
// 这里再进行质量压缩的意义不大,反而耗资源,删除
return bitmap;
}
- 实际开发中,可能需要我们压缩图片的存储大小,比如2M压缩到1M,这叫质量压缩。质量压缩的是图片在存储空间中的大小,和图片加载到内存中占用的内存大小无关。
/**
* 存储Bitmap,并质量压缩,不大于maxSize(kb)
*
* @param image
* @param outPath
* @param maxSize
*
*/
public static void compressAndGenImage(Bitmap image, String outPath,int maxSize) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 压缩度,100为不压缩
int options = 100;
image.compress(Bitmap.CompressFormat.JPEG, options, os);
// 循环压缩
while (os.toByteArray().length / 1024 > maxSize) {
// Clean up os
os.reset();
// 每次递减10
options -= 10;
image.compress(Bitmap.CompressFormat.JPEG, options, os);
}
FileOutputStream fos = new FileOutputStream(outPath);
fos.write(os.toByteArray());
fos.flush();
fos.close();
}