示例:
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.car);
...
bitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.car));
一般通过Bitmap创建的话需要先事先有一个Bitmap对象,或者通过自己指定一些像素属性。
BitmapFactory基本用语将一个图片资源变为解码成Bitmap对象。
/**
* 返回Bitmap对象像素所占内存大小
*
* As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
* no longer be used to determine memory usage of a bitmap. See {@link
* #getAllocationByteCount()}.
*/
public final int getByteCount() {
if (mRecycled) {
Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "
+ "This is undefined behavior!");
return 0;
}
// int result permits bitmaps up to 46,340 x 46,340
return getRowBytes() * getHeight();
}
此方法在19之后就不能在用于定位Bitmap对象内存使用的情况,需要用getAllocationByteCount
/**
* Returns the size of the allocated memory used to store this bitmap's pixels.
*
* This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
* decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
* #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
* #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
* BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
* the same as that returned by {@link #getByteCount()}.
*
* This value will not change over the lifetime of a Bitmap.
*
* @see #reconfigure(int, int, Config)
*/
public final int getAllocationByteCount() {
if (mRecycled) {
Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
+ "This is undefined behavior!");
return 0;
}
return nativeGetAllocationByteCount(mNativePtr);
}
如果位图没有重新以BitmapFactory.Options.inBitmap方式设置Bitmap对象,改方法返回的值和getByteCount一样。
所以就需要封装一个针对不同版本的方法
public static int getBitmapSize(Bitmap bitmap){
if (bitmap == null) {
return 0;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //api 19
return bitmap.getAllocationByteCount();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1){ //api 12
return bitmap.getByteCount();
}
return bitmap.getRowBytes() * bitmap.getHeight(); //other version
}
public class BitmapFactory {
private static final int DECODE_BUFFER_SIZE = 16 * 1024;
public static class Options {
.....
}
}
Options 是BitmapFactory 中的一个静态内部类。内置一些Bitmap对象的属性。
Options 的API文档
博客介绍,很详细
/**
* 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.
*/
public boolean inJustDecodeBounds;
Options 有个属性inJustDecodeBounds,改属性为true的时候不会返回一个Bitmap对象,但是属性仍然会被设置到Options 对象中。
/**
* If set to a value > 1, requests the decoder to subsample the original
* image, returning a smaller image to save memory. The sample size is
* the number of pixels in either dimension that correspond to a single
* pixel in the decoded bitmap. For example, inSampleSize == 4 returns
* an image that is 1/4 the width/height of the original, and 1/16 the
* number of pixels. Any value <= 1 is treated the same as 1. Note: the
* decoder uses a final value based on powers of 2, any other value will
* be rounded down to the nearest power of 2.
*/
public int inSampleSize;
inSampleSize属性如果大于1,则会四舍五入到2的次方,然后缩小该倍数。如果值小于1,则等同于1 。
如:=4的话表示缩小4倍。=5的话也是4倍。效果是一样的。
private Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
BitmapFactory.Options opts = new BitmapFactory.Options();
//设置true
opts.inJustDecodeBounds = true;
//不返回Bitmap对象,但是opts属性照样设置
BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
//根据目标宽高和原始宽高计算比例
int scaleWidth = opts.outWidth / newWidth;
int scaleHeight = opts.outHeight / newHeight;
//取出缩放比例小的一方
//opts.inSampleSize = Math.min(scaleWidth,scaleHeight);
opts.inSampleSize = 4;
//比例设置好后,inJustDecodeBounds设置为false
opts.inJustDecodeBounds = false;
//得到缩放后的bitmap对象
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
....
}
示例中写了固定的比例。如果把得到缩放后的Bitmap对象,重新设置到ImageView中就会发现,变模糊了。
Android中图片有四种属性,分别是:
ALPHA_8:每个像素占用1byte内存
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存 (默认)
RGB_565:每个像素占用2byte内存
Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。 所以在对图片效果不是特别高的情况下使用RGB_565(565没有透明度属性)
BitmapFactory.Options opts = new BitmapFactory.Options();
//设置true
opts.inJustDecodeBounds = true;
//不返回Bitmap对象,但是opts属性照样设置
BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
//像素占内存改小
opts.inPreferredConfig = Bitmap.Config.RGB_565;
//根据目标宽高和原始宽高计算比例
int scaleWidth = opts.outWidth / newWidth;
int scaleHeight = opts.outHeight / newHeight;
//取出缩放比例小的一方
//opts.inSampleSize = Math.min(scaleWidth,scaleHeight);
// opts.inSampleSize = 4;
//比例设置好后,inJustDecodeBounds设置为false
opts.inJustDecodeBounds = false;
//得到缩放后的bitmap对象
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
利用的就是inBitmap指定将要重复利用的Bitmap对象的内存。同时需要指定inMutable=true表示对象是可变的。如果inPreferredConfig = android.graphics.Bitmap.Config.HARDWARE,inMutable属性永远为false。
可以看看下面博客中的图片加一理解
别人的博客,保存下