初識Android Bitmap

Bitmap

Drawable,Canvas和Bitmap

  • drawable:通用的圖形對象,用于裝載常用格式的圖像,既可以是PNG,JPG,gif這樣的圖像。同時包含13種Drawable類型的可視化對象,StateListDrawable,BitmapDrawable...
  • Canvas:畫布,也就是我們可以繪制的區域。提供了drawXXX()等方法來便捷的繪制圖形。
  • Bitmap:是一種存儲像素的數據結構,通過這個對象可以得到一系列的圖像屬性。還可以對圖像進行旋轉,切割,放大,縮小等操作。

個人理解:Bitmap是一種數據結構,存儲像素信息。Drawable 儲存的是 對 Canvas 的一系列操作。而 BitmapDrawable 儲存的是「把 Bitmap 渲染到 Canvas 上」這個操作。

Bitmap,BitmapFactory,BitmapFacotry.Options

獲取Bitmap

由于Bitmap的構造方法私有化,所以我們不能在外部直接實例化一個Bitmap對象。我們只能通過BitmapFactory來得到Bitmap對象。

BitmapFractory常用獲取Bitmap的方法:

途徑 方法
從文件中解析 decodeFile(String pathName, Options), decodeFile(String pathName)
從res/目錄下解析 decodeResource(Resources res,int id), decodeResurce(Resources res, int id, Options)
從字節數組中解析 decodeByteArray(byte[] data, int offset, int length), decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
從流中解析 decodeStream(InputStream is), decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)

通過上述表格我們發現,無論是哪一種途徑得到的Bitmap都有一種重載方法的參數列中多了一個BitmapFacotry.Options參數。那么BitmapFacotry.Options是干嘛的呢?

舉個例子,我們為了縮放圖像想要獲取該圖像的大小,那么首先要在代碼中獲取這個圖像的Bitmap對象,然后通過Bitmap.getWidth()和getheight()方法來獲取圖像的大小。但是如果想要獲取一個大圖像的大小,在得到Bitmap對象時會造成oom。這時我們就可以用到BitmapFractory.Options對象的inJustDecodeBounds字段。操作方法:

  • 首先獲取一個Options對象,并將inJustDecodeBounds設置為True。
  • 然后選擇一種獲取Bitmap途徑的方法,并傳入Options對象。此時該方法返回的Bitmap為null。
  • 然后通過Options.outWidth和outHeight來獲取院士圖片的大小
  • 通過設置Options.inSampleSize來決定獲取Bitmap時縮小圖像長寬的系數。
  • 最后我們把Options實例的inJustDecodeBounds設置為false,并通過該實例獲取大圖像的Bitmap。這樣就防止了OOM

BitmapFactory.Options類有一個參數inSampleSize,該參數為int型,他的值指示了在解析圖片為Bitmap時在長寬兩個方向上像素縮小的倍數。inSampleSize的默認值和最小值為1(當小于1時,解碼器將該值當做1來處理),且在大于1時,該值只能為2的冪(當不為2的冪時,解碼器會取與該值最接近的2的冪)。參考博文高效使用Bitmaps(一) 大Bitmap的加載,BitmapFactory.Options詳解

Bitmap常用方法

  • public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) 將位圖的壓縮到指定的OutputStream,可以理解成將Bitmap保存到文件中!
    • format:格式,PNG,JPG等;
    • quality:壓縮質量,0-100,0表示最低畫質壓縮,100最大質量(PNG無損,會忽略品質設定)
    • stream:輸出流
    • 返回值代表是否成功壓縮到指定流!
  • void recycle():回收位圖占用的內存空間,把位圖標記為Dead
  • boolean isRecycled():判斷位圖內存是否已釋放
  • int getWidth():獲取位圖的寬度
  • int getHeight():獲取位圖的高度
  • boolean isMutable():圖片是否可修改
  • int getScaledWidth(Canvas canvas):獲取指定密度轉換后的圖像的寬度
  • int getScaledHeight(Canvas canvas):獲取指定密度轉換后的圖像的高度
  • Bitmap createBitmap(Bitmap src):以src為原圖生成不可變得新圖像
  • Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter):以src為原圖,創建新的圖像,指定新圖像的高寬以及是否變。
  • Bitmap createBitmap(int width, int height, Config config):創建指定格式、大小的位圖
  • Bitmap createBitmap(Bitmap source, int x, int y, int width, int
    height)以source為原圖,創建新的圖片,指定起始坐標以及新圖像的高寬。
  • public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
    Matrix m, boolean filter)

BitmapFractory.Options字段

  • boolean inJustDecodeBounds——如果設置為true,不獲取圖片,不分配內存,但會返回圖片的高寬度信息。
  • int inSampleSize——圖片縮放的倍數。如果設為4,則寬和高都為原來的1/4,則圖是原來的1/16。
  • int outWidth——獲取圖片的寬度值
  • int outHeight——獲取圖片的高度值
  • int inDensity——用于位圖的像素壓縮比
  • int inTargetDensity——用于目標位圖的像素壓縮比(要生成的位圖)
  • boolean inScaled——設置為true時進行圖片壓縮,從inDensity到inTargetDensity。

獲取Bitmap實例

從資源中獲取位圖的方式有兩種:通過BitmapDrawable或者BitmapFactory。

BitmapDrawable

Android支持三種格式的位圖圖像:.png (preferred),.jpg (acceptable), .gif (discouraged)。
括號里的說明,代表這三種格式的圖片在Android中的支持情況,.png格式圖片優先,.jpg格式也可以,但是效果沒有.png好,.gif支持最差。

在構建應用的時候,Bitmap文件可能會被appt工具壓縮自動優化為無損圖像。例如,一個真彩色PNG,不需要超過256的顏色可以被轉換成一個8位PNG和調色板。這將導致一個圖像質量相同,但這需要更少的內存。所以要意識到,在drawable目錄中圖像的二進制文件在構建程序時可以改變。如果你打算讀一個圖像作為字節流并將它轉換成一個位圖,把你的圖片放在在res /raw/文件夾里,在那里他們不會被優化。參考博文Android Drawable Resource學習(二)、BitmapDrawable和Bitmap

獲取BitmapDrawable

  • Bitmap file
    我們可以直接從res/drawable目錄下的圖片文件(.jpg,.png,.gif)獲取drawable對象,并將其轉型為BitmapDrawable

res/drawable目錄下的圖片文件(.jpg,.png,.gif)編譯資源數據類型:指向BitmapDrawable類型的指針。

  • XML Bitmap:
    一個XML bitmap是一個在XML文件中定義的指向一個bitmap文件的資源。其效果是作為一個原始位圖文件的別名,并且可以指定一些額外的屬性。<bitmap>是Bitmap XML的根標簽,它有很多屬性設置,實現平鋪、拉伸或保持圖片原始大小,也可以指定對齊方式等效果。可以參考博文Android樣式的開發:drawable匯總篇

同樣編譯資源類型指向BitmapDrawable類型的指針

Drawable向下轉型

Resources res=getResources();  
Drawable drawable = res.getDrawable(R.drawable.file_name);  
//實際上這是一個BitmapDrawable對象  
BitmapDrawable bitmapDrawable=(BitmapDrawable)drawable;  
//可以在調用getBitmap方法,得到這個位圖  
Bitmap bitmap=bitmapDrawable.getBitmap(); 

BitmapDrawable構造方法

InputStream is=res.openRawResource(R.drawable.file_name);
BitmapDrawable bmpDraw=new BitmapDrawable(is);
Bitmap bmp=bmpDraw.getBitmap();

還有其他構造方法,可以查閱官方文檔

Bitmap 2 BitmapDrawable

Drawable drawable = new BitmapDrawable(bitmap);

BitmapFactory

通過上述表格中各種途徑的靜態方法來獲取Bitmap

//res/drawable目錄下資源id獲取
BitmapFactory.decodeResource(res, resId);
//文件路徑獲取
BitmapFactory.decodeFile(pathName);
//輸入流獲取
BitmapFactory.decodeStream(inputStream);

字節流

從字節流獲取Bitmap

public Bitmap Bytes2Bimap(byte[] b) {  
    if (b.length != 0) {  
        return BitmapFactory.decodeByteArray(b, 0, b.length);  
    } else {  
        return null;  
    }  
} 

Bitmap轉換為字節流

public byte[] Bitmap2Bytes(Bitmap bm) {  
    ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    bm.compress(Bitmap.CompressFormat.PNG, 100, baos);  
    return baos.toByteArray();  
}  

Bitmap.Config

在Bitmap類里createBitmap(intwidth, int height, Bitmap.Config config)方法里有一個參數Bitmap.Config是用來做什么的呢?

要解決Bitmap的OOM問題可以有兩種方法:

  • 壓縮大圖片的大小,縮放
  • 改變大圖片的色彩存儲方法

那么Bitmap.Config就是圖片存儲顏色。在Bitmap.Config文檔中我們看到四個枚舉變量。

  • Bitmap.Config : ALPHA_8, 就是Alpha由8位組成
  • Bitmap.Config : ARGB_4444, 就是由4個4位組成即16位,
  • Bitmap.Config : ARGB_8888, 就是由4個8位組成即32位,
  • Bitmap.Config : RGB_565, 就是R為5位,G為6位,B為5位共16位

ARGB指的是一種色彩模式,里面A代表Alpha,R表示red,G表示green,B表示blue,其實所有的可見色都是右紅綠藍組成的,所以紅綠藍又稱為三原色,每個原色都存儲著所表示顏色的信息值。位圖位數越高代表其可以存儲的顏色信息越多,當然圖像也就越逼真。

參考博文android圖片壓縮質量參數Bitmap.Config RGB_565等的含義

Bitmap縮放

public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        float srcWidth = options.outWidth;
        float srcHeight = options.outHeight;

        int inSampleSize = 1;
        if(srcHeight > destHeight || srcWidth > destWidth) {
            if(srcWidth > srcHeight) {
                inSampleSize = Math.round(srcHeight / destHeight);
            } else {
                inSampleSize = Math.round(srcWidth /destWidth);
            }
        }

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

        return BitmapFactory.decodeFile(path, options);
    }

參考

android圖片壓縮質量參數Bitmap.Config RGB_565等的含義

Android基礎入門教程——8.2.1 Bitmap(位圖)詳解

高效使用Bitmaps(一) 大Bitmap的加載,BitmapFactory.Options詳解

Android樣式的開發:drawable匯總篇

【Android】Drawable、Bitmap、Canvas、Paint之間區別

目標

  • 圖片的兩種解決OOM問題
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容