Bitmap
是 Android 系统中图像处理的最重要的类之一。通过Bitmap
我们可以获取到图片的信息(宽度的像素值,高度的像素值,总的像素值,α 值,还可以通过Bitmap
去创建一个新的Bitmap
等)。获取到信息之后,可以对其进行缩放、裁剪等操作。
Bitmap 加载方式
BitmapFactory.decodeByteArray() // 将 字节数组 decode 成 Bitmap
BitmapFactory.decodeFile() // 将 文件 decode 成 Bitmap
BitmapFactory.decodeResource() // 将 资源 decode 成 Bitmap
BitmapFactory.decodeStream() // 将 流 decode 成 Bitmap
示例:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, null);
Q: 为什么是
Bitmap bitmap = BitmapFactory.decodeXxx
而不是Bitmap bitmap = new Bitmap()
?
A: 因为Bitmap
可能会非常的占用内存,所以系统帮我们创建了一个工厂类来decode
不同的Bitmap
,而且Bitmap
本生方法是私有的,不允许我们直接 new 一个Bitmap
。
高效加载
图片是一个对内存消耗很大的事物,目前主流手机的像素都是千万像素的,一张照片就会达到几兆~几十兆,我们不应该把这么大的一个事物直接加载到内存里,容易导致 OOM(内存溢出),所以我们应该尽可能的节省内存开销,使应用运行的更加流畅。
关键字:BitmapFactory.Options
官方API文档:https://developer.android.google.cn/reference/android/graphics/BitmapFactory.Options
BitmapFactory.Options 有如下几个重要的属性:
说明:
inJustDecodeBounds
是boolean
型变量,如果把它设置为true
,在BitmapFactory.decodeXxx
的时候并不会真正的返回一个Bitmap
而是返回Bitmap
的width
和height
,而且把这个width
和height
传到outWidth
和outHeight
这两个字段中。inSampleSize
是采样率,通过这个采样率我们可以极大的减少图片内存占用。
示例(对图片进行压缩,并打印出压缩前后图片占用内存大小):
1. 自定义压缩图片方法
/**
*
*
* @param filePath 图片路径
* @param width 要显示的图片宽度
* @param height 要显示的图片高度
* @return 压缩后图片
*/
private Bitmap ratioBitmap(String filePath, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 目的:只加载图片的宽和高,而不加载图片的真正内容
options.inPreferredConfig = Bitmap.Config.ARGB_8888; // 设置图片解码时使用的颜色模式
// 预加载
BitmapFactory.decodeFile(filePath, options);
// 获取图片宽高
int originalWidth = options.outWidth;
int originalHeight = options.outHeight;
// 加载图片的真正内容
options.inJustDecodeBounds = false;
// 对图片进行采样
options.inSampleSize = getSampleSize(originalWidth, originalHeight, width, height);
return BitmapFactory.decodeFile(filePath, options);
}
2. 自定义获取采样率方法
/**
* 获取采样率
*
* @param originalWidth 原始图片宽度
* @param originalHeight 原始图片高度
* @param width 要显示的图片宽度
* @param height 要显示的图片高度
* @return 采样率
*/
private int getSampleSize(int originalWidth, int originalHeight, int width, int height) {
// 初始化采样率
int sampleSize = 1;
if (originalWidth > originalHeight && originalWidth > width) {
// 用宽度计算采样率
sampleSize = originalWidth / width;
} else if (originalWidth < originalHeight && originalHeight > height) {
Log.d(TAG, "originalHeight: " + originalHeight);
Log.d(TAG, "height: " + height);
// 用高度计算采样率
sampleSize = originalHeight / height;
}
if (sampleSize <= 0) {
sampleSize = 1;
}
return sampleSize;
}
3. 对本地图片进行压缩
图片路径
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "demo.png";
未压缩的图片
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
Log.d(TAG, "未压缩的图片: " + bitmap.getByteCount());
压缩后的图片
bitmap = ratioBitmap(filePath, mIv.getWidth(), mIv.getHeight());
Log.d(TAG, "压缩后的图片: " + bitmap.getByteCount());
(注: mIv 就是一个简单的 ImageView,宽高随意设置,这里布局文件就不贴出来了)
Log 日志
未压缩的图片: 3686400
压缩后的图片: 921600
通过对比可以看到,压缩的大小还是很明显的。
网友评论