- 实例化对象
- Bitmap对象大小和像素大小
- BitmapFactory.Options
如何实例化对象
- Bitmap文档
Bitmap提供了一系列的createXX方法,可以通过:Bitmap、DisplayMetrics、Picture、RGB的颜色数组等得到一个Bitmap对象。 - BitmapFactory提供了一系列的decodeXX方法。流行、文件、资源等得到一个Bitmap对象。
示例:
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.car);
...
bitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.car));
一般通过Bitmap创建的话需要先事先有一个Bitmap对象,或者通过自己指定一些像素属性。
BitmapFactory基本用语将一个图片资源变为解码成Bitmap对象。
Bitmap对象大小和像素大小。
/**
* 返回Bitmap对象像素所占内存大小
*
* <p>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()}.</p>
*/
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.
*
* <p>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()}.</p>
*
* <p>This value will not change over the lifetime of a Bitmap.</p>
*
* @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
}
BitmapFactory.Options
- Options
public class BitmapFactory {
private static final int DECODE_BUFFER_SIZE = 16 * 1024;
public static class Options {
.....
}
}
Options 是BitmapFactory 中的一个静态内部类。内置一些Bitmap对象的属性。
Options 的API文档
博客介绍,很详细
- 简单压缩图片
有一些场景,对图片的显示质量要求不高,这样我们就没有必要去加载高清原图了。直接显示压缩后的图片,需要解决两个问题:- 如何不用创建Bitmap对象就获得原图的宽高大小呢?
/**
* If set to true, the decoder will return null (no bitmap), but
* the <code>out...</code> 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);
log之后发现宽高不变,像素变小了。
内存空间复用
利用的就是inBitmap指定将要重复利用的Bitmap对象的内存。同时需要指定inMutable=true表示对象是可变的。如果inPreferredConfig = android.graphics.Bitmap.Config.HARDWARE,inMutable属性永远为false。
可以看看下面博客中的图片加一理解
别人的博客,保存下