二次采样是为了避免图片加载时的OOM异常。
1.第一次采样
第一次采样我主要是想要获得图片的压缩比例,假如说我有一张图片是200*200,那么我想把这张图片的缩略图显示在一个50*50的ImageView上,那我的压缩比例应该为4,那么这个4应该怎么样来获得呢?这就是我们第一步的操作了,我先加载图片的边界到内存中,这个加载操作并不会耗费多少内存,加载到内存之后,我就可以获得这张图片的宽高参数,然后根据图片的宽高,再结合控件的宽高计算出缩放比例。
2.第二次采样
在第一次采样的基础上,我来进行二次采样。二次采样的时候,我把第一次采样后算出来的结果作为一个参数传递给第BitmapFactory,这样在加载图片的时候系统就不会将整张图片加载进来了,而是只会加载该图片的一张缩略图进来,这样不仅提高了加载速率,而且也极大的节省了内存,而且对于用户来说,他也不会有视觉上的差异。
package com.xiaoyehai.threadpool;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
/**
* 对图片进行二次采样的工具类
* Created by xiaoyehai on 2016/12/30.
*/
public class CompressImageUtil {
/**
* 对资源文件中的图片进行压缩
*
* @param context 上下文对象
* @param imageId 压缩图片的id
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件高度
* @return
*/
public static Bitmap getBitmap(Context context, int imageId, int destWidth, int destHeight) {
//创建一个可选项对象,该对象用于配置图片的处理参数
BitmapFactory.Options options = new BitmapFactory.Options();
//第一次采样,该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点,也就是说不会把图片加载到内存中
options.inJustDecodeBounds = true;
//加载图片,该方法只是从图片文件中读取图片的宽和高信息,而没有真正的加载到内存中
BitmapFactory.decodeResource(context.getResources(), imageId, options);
//获取图片的宽和高
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
//定义缩放比例
int sampleSize = 1;
while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
//如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例
//sampleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值
sampleSize *= 2;
}
//第二次采样,使用缩放比例进行缩放加载图,加载器就会返回图片了
options.inJustDecodeBounds = false;
//设置压缩比
options.inSampleSize = sampleSize;
/**
* inPreferredConfig设置图片的质量:
* ARGB_8888:默认的图片质量,也是最好的质量,32位,4个字节
* ARGB_4444:是ARGB_8888占用内存的一半,但质量比较低,不推荐使用
* RGB_565:不带透明度,是ARGB_8888占用内存的一半,质量不错,推荐使用
*/
//设置图片质量
options.inPreferredConfig = Bitmap.Config.RGB_565;
//返回压缩后的图片
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), imageId, options);
//Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
return bitmap;
}
/**
* 对内存卡中的图片进行压缩
*
* @param path 图片路径
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件高度
* @return
*/
public static Bitmap getBitmap(String path, int destWidth, int destHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
int sampleSize = 1;
while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
sampleSize *= 2;
}
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
//Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
return bitmap;
}
/**
* 通过网络请求返回的字节数据进行二次采样并返回bitmap
*
* @param bytes
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件高度
* @return
*/
public static Bitmap getBitmap(byte[] bytes, int destWidth, int destHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
int sampleSize = 1;
while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
sampleSize *= 2;
}
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
// Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
return bitmap;
}
}