在使用Bitmap(位图)中,我们总是会与BitmapFactory类打交道。今天就来看看BitmapFactory的庐山真面目。
首先依旧是看看官网的定义:
Creates Bitmap objects from various sources, including files, streams, and byte-arrays.
翻译:BitmapFactory 用于从各种资源、文件、流和字节数组中创建Bitmap(位图)对象。
简而言之,就是说使用BitmapFactory类就可以创建Bitmap(位图)了。(当然,创建Bitmap(位图)还有其他方式,下篇文章会讲解)接下来,我们就看看系统提供的BitmapFactory类提供的用于创建Bitmap(位图)的方法。BitmapFactory类是一个工具类,提供大量方法,这些方法可用于从不同的数据源解析、创建Bitmap(位图)。
一. BitmapFactory 类创建Bitmap(位图)的方法说明。
1. public static Bitmap decodeByteArray (byte[] data, int offset, int length, BitmapFactory.Options opts)
参数
data 压缩图像数据的字节数组
offset 图像数据偏移量,用于解码器开始从哪儿解析.
length 字节数,以偏移量开始,去解析
opts 可以为空,控制采样率和实付图像完全被解码的选项,或者仅仅返回大小
返回值
返回解码后的位图,或者如果图像数据不能被解码返回为空,或者 如果选项不是空,如果选项要求仅仅返回大小(opts.outWidth and opts.outHeight)。
从指定的字节数组中解码一个不可变的位图。
2. public static Bitmap decodeByteArray (byte[] data, int offset, int length)
参数
data 压缩图像数据的字节数组
offset 图像数据偏移量,用于解码器开始从哪儿解析.
length 字节数,以偏移量开始,去解析
返回值
返回解码后的位图,或者如果图像数据不能被解码返回为空
从指定的字节数组中解码一个不可变的位图。
3. public static Bitmap decodeFile (String pathName)
参数
pathName 解码文件的全路径名
返回值
返回结果是解码的位图,或者如果不能解码则返回空。
从文件中解码生成一个位图。如果支付的文件名为空,或者不能解码出一个位图,方法将返回空。
4. public static Bitmap decodeFile (String pathName, BitmapFactory.Options opts)
参数
pathName 解码文件的全路径名
opts 可以为空,控制采样率和实付图像完全被解码的选项,或者仅仅返回大小
Returns
返回解码后的位图,或者如果图像数据不能被解码返回为空,或者 如果选项不是空,如果选项要求仅仅返回大小(opts.outWidth and opts.outHeight)。
从文件中解码生成一个位图。如果支付的文件名为空,或者不能解码出一个位图,方法将返回空。
5. public static Bitmap decodeFileDescriptor (FileDescriptor fd)
参数
fd 包含解码位图数据的文件路径
返回值
返回解码的位图或者空。
从<span style="font-family: Arial, Helvetica, sans-serif;">文件路径</span><span style="font-family: Arial, Helvetica, sans-serif;">中解码位图。如果不能解码问题返回空。当返回的时候,描述符的位置不会改变,因此可以再次使用描述符。</span>
6. public static Bitmap decodeFileDescriptor (FileDescriptor fd, Rect outPadding, BitmapFactory.Options opts)
参数
fd 包含解码位图数据的<span style="font-family: Arial, Helvetica, sans-serif;">文件路径</span>
outPadding 如果不为空,返回矩形的内边距如果位图存在,否则设置内边距为(-1,-1,-1,-1).如果没有位图返回空,内边距不改变
opts 可以为空,控制采样率和实付图像完全被解码的选项,或者仅仅返回大小
返回值
返回解码的位图或者空。
从<span style="font-family: Arial, Helvetica, sans-serif;">文件路径</span><span style="font-family: Arial, Helvetica, sans-serif;">解码位图。如果不能解码问题返回空。当返回的时候,描述符的位置不会改变,因此可以再次使用描述符。</span>
7. public static Bitmap decodeResource (Resources res, int id, BitmapFactory.Options opts)
参数
res 包含图像数据的资源对象
id 图像数据的资源的id
opts 可以为空,控制采样率和实付图像完全被解码的选项,或者仅仅返回大小
返回值
返回解码后的位图,或者如果图像数据不能被解码返回为空,或者 如果选项不是空,如果选项要求仅仅返回大小(opts.outWidth and opts.outHeight)。
打开给的资源获取位图,与decodeResourceStream(Resources, TypedValue, InputStream, Rect, BitmapFactory.Options)同义。
8. public static Bitmap decodeResourceStream (Resources res, TypedValue value, InputStream is, Rect pad, BitmapFactory.Options opts)
从输入流中解码一个新位图。输入了获得资源,我们可以缩放位图。
9. public static Bitmap decodeResource (Resources res, int id)
参数
res 包含图像数据的资源对象
id 图像数据的资源的id
返回值
返回解码后的位图,或者如果图像数据不能被解码返回为空
从输入流中解码位图。与decodeResource(Resources, int, android.graphics.BitmapFactory.Options)当Options是空时同义,
10. public static Bitmap decodeResource (Resources res, int id, BitmapFactory.Options opts)
参数
res 包含图像数据的资源对象
id 图像数据的资源的id
opts 可以为空,控制采样率和实付图像完全被解码的选项,或者仅仅返回大小
返回值
返回解码后的位图,或者如果图像数据不能被解码返回为空,或者 如果选项不是空,如果选项要求仅仅返回大小(opts.outWidth and opts.outHeight)。
从资源中解码一个位图。与decodeResourceStream(Resources, TypedValue, InputStream, Rect, BitmapFactory.Options)同义.
11. public static Bitmap decodeStream (InputStream is, Rect outPadding, BitmapFactory.Options opts)
参数
is 持有原始数据用于解码位图的输入流
outPadding 如果不为空,返回矩形的内边距如果位图存在,否则设置内边距为(-1,-1,-1,-1).如果没有位图返回空,内边距不改变
opts 可以为空,控制采样率和实付图像完全被解码的选项,或者仅仅返回大小
Returns
返回解码后的位图,或者如果图像数据不能被解码返回为空,或者 如果选项不是空,如果选项要求仅仅返回大小(opts.outWidth and opts.outHeight)。
从输入流中解码一个位图。如果输入了为空,或者不能解码位图,方法返回空。流的位置觉得解码数据从哪儿读取。
12. public static Bitmap decodeStream (InputStream is)
Decode an input stream into a bitmap. If the input stream is null, or cannot be used to decode a bitmap, the function returns null. The stream's position will be where ever it was after the encoded data was read.
参数
is 持有原始数据用于解码位图的输入流
返回值
返回解码后的位图,或者如果图像数据不能被解码返回为空
从输入流中解码一个位图。如果输入了为空,或者不能解码位图,方法返回空。流的位置觉得解码数据从哪儿读取。
以上就是BitmapFactory 类创建Bitmap(位图)的方法汇总。上面列举的方法中,有一个参数比较重要就是BitmapFactory.Options类,下面,我们看看BitmapFactory.Options类的说明以及使用。
二. BitmapFactory.Options说明以及使用。
还是依旧看官方的定义:
Create a default Options object, which if left unchanged will give the same result from the decoder as if null were passed.
翻译:创建默认选项对象,如果保持不变将从解码器得到相同的结果,如果是空则通过。
换句话说,就是设置这个值,可以更好的控制、显示、使用Bitmap(位图)。我们在实际开发中,可以灵活的使用该值,就可能会减少OOM的发生。是不是很高兴很激动呢!。下面,我们就介绍几个BitmapFactory.Options类比较重要的属性值。
2.1 inJustDecodeBounds。
先看看定义:
boolean inJustDecodeBounds
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
翻译:如果设置为真,解码将返回空(没有位图),但是输出的字段依然被设置,允许调用者查询
Bitmap(位图)而不用为其像素分配内存。
也就是说,我们想要获取位图的宽和高时,可以设置inJustDecodeBounds为'true',那么此时并不会返回一个Bitmap(位图),并且位图不会占用内存,但是会返回位图的宽和高。options.outWidth 和 options.outHeight就是我们想要的宽和高。具体代码示例如下,(是Android官方给的计算代码)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
PS: BitmapFactory获取图片的宽、高信息和图片的位置信息以及程序运行的设备有关,比如同一张图片放在不同的drawable目录下,或者程序运行在不同屏幕密码的设备上着都可能导致BitmapFactory获取到不同的结果,之所以会这样,这和Android的资源加载机制有关,相信读者平时里肯定有所体会。
除了设置inJustDecodeBounds,我们可以设置inSampleSize属性,达到合理使用内存。
2.2 inSampleSize。
采样率,设置它,可以缩放图片。官方建议取值为2的幂数,比如1、2、4、8、16等。例如,当设置inSampleSize=1时,采样后的图片大小为图片的原始大小;inSampleSize大于1时,比如2,那么采样后的图片宽/高均为原图大小的1/2,总像素为原图的1/4,其占用内存也为原图的1/4,例如一张1024*1024的像素图片,假如采用ARGB_8888格式存储,它占用的内存大小大约是=1024*1024*4=4MB。如果inSampleSize=2,那么采样后的图片其内存占用是512*512*4=1MB。如果inSampleSize小于1,则按1处理;其他任何值将四舍五入到最接近2的幂数!我们可以动态计算inSampleSize的值,如下所示,
(1). 计算inSampleSize的值,(是Android官方给的计算代码)
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
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;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
上述代码可以看出,计算的结果肯定是2的幂数。
接下来,我们结合inJustDecodeBounds和inSampleSize这两个属性,看看如何共同使用,示例代码如下:(是Android官方给的计算代码)
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
首先设置inJustDecodeBounds为‘true’,计算出位图的宽、高,然后在计算inSampleSize的值,再次设置
nJustDecodeBounds为‘false’,最后调用BitmapFactory.decodeResource()方法解码位图。是不是比较简单呢!
例如加载一张图片至ImageView,大小为100*100,代码如下所示: (是Android 官方给的计算代码 )
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
上述几段代码,均来自Android官方的文档。推荐大家有时间,可以仔细看看官方文档!
下面,我们就使用BitmapFactory来创建Bitmap(位图)。
三. BitmapFactory来创建Bitmap(位图),示例代码如下,
(1). Bitmap工具类。
/**
* Bitmap工具类
*/
public class BitmapUtils {
/**
* @param res
* @param id
* @param opts
* @return
*/
public static Bitmap decodeResource(Resources res, int id,
BitmapFactory.Options opts) {
return BitmapFactory.decodeResource(res, id, opts);
}
/**
* @param res
* @param id
* @return
*/
public static Bitmap decodeResource(Resources res, int id) {
return BitmapFactory.decodeResource(res, id);
}
/**
* @param pathName
* @return
*/
public static Bitmap decodeFile(String pathName) {
return BitmapFactory.decodeFile(pathName);
}
/**
* @param pathName
* @param opts
* @return
*/
public static Bitmap decodeFile(String pathName, BitmapFactory.Options opts) {
return BitmapFactory.decodeFile(pathName, opts);
}
/**
* @param is
* @return
*/
public static Bitmap decodeStream(InputStream is) {
return BitmapFactory.decodeStream(is);
}
}
(2). 生成 Bitmap(位图),
//从drawable中获取
bitmap=BitmapUtils.decodeResource(getResources(), R.drawable.iv_mt_ic);
//从assets中获取
try {
InputStream is=this.getAssets().open("iv_dzdp_iv.png");
bitmap=BitmapUtils.decodeStream(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//从sdcard中获取
String path="/sdcard/img.jpg";
bitmap=BitmapUtils.decodeFile(path);
三. 总结。
实际开发中,使用BitmapFactory创建Bitmap(位图)还是比较多的,结合BitmapFactory.Options类,可以更方便、快捷!本篇文章介绍BitmapFactory就到此!希望对你有所帮忙!如有描述错误,请指出!