BitmapFactory.Options詳解

public Bitmapjava

inBitmapandroid

If set, decode methods that take the Options object will attempt to reuse this bitmap when loading content.算法

public intapp

inDensityide

The pixel density to use for the bitmap.this

public booleanspa

inDithercode

If dither is true, the decoder will attempt to dither the decoded image.圖片

public boolean內存

inInputShareable

This field works in conjuction with inPurgeable.

public boolean

inJustDecodeBounds

If set to true, the decoder will return null (no bitmap), but the out…

public boolean

inMutable

If set, decode methods will always return a mutable Bitmap instead of an immutable one.

public boolean

inPreferQualityOverSpeed

If inPreferQualityOverSpeed is set to true, the decoder will try to decode the reconstructed image to a higher quality even at the expense of the decoding speed.

publicBitmap.Config

inPreferredConfig

If this is non-null, the decoder will try to decode into this internal configuration.

public boolean

inPurgeable

If this is set to true, then the resulting bitmap will allocate its pixels such that they can be purged if the system needs to reclaim memory.

public int

inSampleSize

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.

public boolean

inScaled

When this flag is set, if inDensity and inTargetDensity are not 0, the bitmap will be scaled to match inTargetDensity when loaded, rather than relying on the graphics system scaling it each time it is drawn to a Canvas.

public int

inScreenDensity

The pixel density of the actual screen that is being used.

public int

inTargetDensity

The pixel density of the destination this bitmap will be drawn to.

public byte[]

inTempStorage

Temp storage to use for decoding.

public boolean

mCancel

Flag to indicate that cancel has been called on this object.

public int

outHeight

The resulting height of the bitmap, set independent of the state of inJustDecodeBounds.

public String

outMimeType

If known, this string is set to the mimetype of the decoded image.

public int

outWidth

The resulting width of the bitmap, set independent of the state of inJustDecodeBounds.

 

這個表格是從android sdk文檔裏摘出來的,簡單看一下說明就明白是什麼意思了。

下面咱們回到咱們的主題上來:怎樣獲取圖片的大小?

思路很簡單:

首先咱們把這個圖片轉成Bitmap,而後再利用Bitmap的getWidth()和getHeight()方法就能夠取到圖片的寬高了。

新問題又來了,在經過BitmapFactory.decodeFile(String path)方法將突破轉成Bitmap時,遇到大一些的圖片,咱們常常會遇到OOM(Out Of Memory)的問題。怎麼避免它呢?

這就用到了咱們上面提到的BitmapFactory.Options這個類。

BitmapFactory.Options這個類,有一個字段叫作 inJustDecodeBounds 。SDK中對這個成員的說明是這樣的:

If set to true, the decoder will return null (no bitmap), but the out…

也就是說,若是咱們把它設爲true,那麼 BitmapFactory.decodeFile(String path, Options opt)並不會真的返回一個Bitmap給你,它僅僅會把它的寬,高取回來給你,這樣就不會佔用太多的內存,也就不會那麼頻繁的發生OOM了。

示例代碼以下:

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

Bitmap bmp = BitmapFactory.decodeFile(path, options);

/* 這裏返回的bmp是null */

這段代碼以後,options.outWidth 和 options.outHeight就是咱們想要的寬和高了。

有了寬,高的信息,咱們怎樣在圖片不變形的狀況下獲取到圖片指定大小的縮略圖呢?

好比咱們須要在圖片不變形的前提下獲得寬度爲200的縮略圖。

那麼咱們須要先計算一下縮放以後,圖片的高度是多少 

/* 計算獲得圖片的高度 */

/* 這裏須要主意,若是你須要更高的精度來保證圖片不變形的話,須要本身進行一下數學運算 */

int height = options.outHeight * 200 / options.outWidth;

options.outWidth = 200;

options.outHeight = height; 

/* 這樣才能真正的返回一個Bitmap給你 */

options.inJustDecodeBounds = false;

Bitmap bmp = BitmapFactory.decodeFile(path, options);

image.setImageBitmap(bmp);

複製代碼

這樣雖然咱們能夠獲得咱們指望大小的ImageView

可是在執行BitmapFactory.decodeFile(path, options);時,並無節約內存。要想節約內存,還須要用到BitmapFactory.Options這個類裏的 inSampleSize 這個成員變量。

咱們能夠根據圖片實際的寬高和咱們指望的寬高來計算獲得這個值。

inSampleSize = options.outWidth / 200;

另外,爲了節約內存咱們還可使用下面的幾個字段:

options.inPreferredConfig = Bitmap.Config.ARGB_4444;    // 默認是Bitmap.Config.ARGB_8888

/* 下面兩個字段須要組合使用 */

options.inPurgeable = true;

options.inInputShareable = true;



用BitmapFactory解碼一張圖片時,有時會遇到該錯誤。這每每是因爲圖片過大形成的。要想正常使用,則須要分配更少的內存空間來存儲。

BitmapFactory.Options.inSampleSize

設置恰當的inSampleSize可使BitmapFactory分配更少的空間以消除該錯誤。inSampleSize的具體含義請參考SDK文檔。例如:

BitmapFactory.Options opts = new BitmapFactory.Options();

opts.inSampleSize = 4;

Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

設置恰當的inSampleSize是解決該問題的關鍵之一。BitmapFactory.Options提供了另外一個成員inJustDecodeBounds。

BitmapFactory.Options opts = new BitmapFactory.Options();

opts.inJustDecodeBounds = true;

Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

設置inJustDecodeBounds爲true後,decodeFile並不分配空間,但可計算出原始圖片的長度和寬度,即opts.width和opts.height。有了這兩個參數,再經過必定的算法,便可獲得一個恰當的inSampleSize。

查看Android源碼,咱們得知,爲了獲得恰當的inSampleSize,Android提供了一種動態計算的方法。

public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
    int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
    int roundedSize;
    if (initialSize <= 8) {
        roundedSize = 1;
        while (roundedSize < initialSize) {
            roundedSize <<= 1;
        }
    } else {
        roundedSize = (initialSize + 7) / 8 * 8;
    }
    return roundedSize;
}

private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
    double w = options.outWidth;
    double h = options.outHeight;
    int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
    int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
    if (upperBound < lowerBound) {
        // return the larger one when there is no overlapping zone.
        return lowerBound;
    }
    if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
        return 1;
    } else if (minSideLength == -1) {
        return lowerBound;
    } else {
        return upperBound;
    }
} 

使用該算法,就可動態計算出圖片的inSampleSize。

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile, opts);
opts.inSampleSize = computeSampleSize(opts, -1, 128*128);  
opts.inJustDecodeBounds = false;
try {
 Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);
 imageView.setImageBitmap(bmp);
    } catch (OutOfMemoryError err) {
    }

綜合上述,完整代碼是:

public static Bitmap createImageThumbnail(String filePath){  
     Bitmap bitmap = null;  
     BitmapFactory.Options opts = new BitmapFactory.Options();  
     opts.inJustDecodeBounds = true;  
     BitmapFactory.decodeFile(filePath, opts);  
  
     opts.inSampleSize = computeSampleSize(opts, -1, 128*128);  
     opts.inJustDecodeBounds = false;  
  
     try {  
         bitmap = BitmapFactory.decodeFile(filePath, opts);  
     }catch (Exception e) {  
        // TODO: handle exception  
    }  
    return bitmap;  
}  
  
public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {  
    int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);  
    int roundedSize;  
    if (initialSize <= 8) {  
        roundedSize = 1;  
        while (roundedSize < initialSize) {  
            roundedSize <<= 1;  
        }  
    } else {  
        roundedSize = (initialSize + 7) / 8 * 8;  
    }  
    return roundedSize;  
}  
  
private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {  
    double w = options.outWidth;  
    double h = options.outHeight;  
    int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));  
    int upperBound = (minSideLength == -1) ? 128 :(int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));  
    if (upperBound < lowerBound) {  
        // return the larger one when there is no overlapping zone.  
        return lowerBound;  
    }  
    if ((maxNumOfPixels == -1) && (minSideLength == -1)) {  
        return 1;  
    } else if (minSideLength == -1) {  
        return lowerBound;  
    } else {  
        return upperBound;  
    }  
}
相關文章
相關標籤/搜索