Android開發中Bitmap的全面總結

Bitmap稱爲位圖,內部結構是像素矩陣排列。它由A、R、G、B通道組成,其中A代表Alpha,R代表Red,G代表Green。我們在開發中,通常把圖片轉爲Bitmap來處理。

一、Bitmap結構類型

Bitmap按照內部結構,分爲6種類型Config:ALPHA_8、RGB_565、ARGB_4444、ARGB_8888、RGBA_F16、HARDWARE。常用類型是RGB_565和ARGB_8888,在Android中默認使用ARGB_8888來創建Bitmap。

ALPHA_8:只使用一個Alpha單通道,共佔1個字節
RGB_565:RGB通道按5:6:5比例排列,共佔2個字節
ARGB_4444:ARGB通道各佔4bits,共佔2個字節(已棄用)
ARGB_8888:ARGB通道各佔8bits,共佔4個字節
RGBA_F16:RGBA通道各佔16bits,共佔8個字節
HARDWARE:適用於只保存在圖像內存的情況,Bitmap不可修改

二、創建Bitmap

Android的API提供創建的Bitmap方法包括:匿名共享內存Bitmap、縮放Bitmap、硬件Bitmap、通用Bitmap。

1、匿名共享內存:createAshmemBitmap(),共享內存利於進程間傳遞

2、縮放:createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)

3、硬件:Bitmap createHardwareBitmap(GraphicBuffer graphicBuffer)

4、通用:createBitmap(int width, int height, Config config)

三、Bitmap拷貝

Bitmap可以拷貝成一個新的Bitmap,也可以拷貝到Buffer中,或者從Buffer拷貝中出來。

1、拷貝新Bitmap:copy(Config config, boolean isMutable),與原Bitmap的像素密度和色彩空間一致

2、像素拷貝到Buffer:copyPixelsToBuffer(Buffer dst),Buffer的像素與原Bitmap保持一致

3、從Buffer拷貝像素:copyPixelsFromBuffer(Buffer src),如果要再次從Buffer讀取,需要先調用rewind方法

四、Bitmap壓縮

Bitmap支持壓縮格式包括:PNG、JPEG、WEBP,可設置壓縮質量0—100。整個過程是把Bitmap壓縮並輸出到指定的OutputStream,以指定格式保存,也就是Bitmap保存爲圖片到內存裏。調用的壓縮方法:compress(CompressFormat format, int quality, OutputStream stream)。提供的壓縮格式:

public enum CompressFormat {
    JPEG    (0),
    PNG     (1),
    WEBP    (2);

    CompressFormat(int nativeInt) {
        this.nativeInt = nativeInt;
    }
    final int nativeInt;
}

五、獲取Bitmap大小

我們可以獲取Bitmap的每行佔用字節數、佔用的總字節數和分配內存的字節數。

1、每行佔用字節數:getRowBytes()

2、佔用的總字節數:getByteCount(),通過每行佔用字節數*高度得出

3、分配內存字節數:getAllocationByteCount(),如果Bitmap有重配置,可能比getByteCount()的結果更大

六、讀寫Bitmap的像素數組

如果要修改Bitmap的像素,我們可以把Bitmap的像素數組讀出來,然後修改,再重新賦值給Bitmap。前提是Bitmap是mutable可修改的,可以通過isMutable()方法來判斷該Bitmap是否支持修改。

1、獲取像素點:getPixel(int x, int y)

2、獲取像素數組:getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)

3、修改像素點:setPixel(int x, int y, @ColorInt int color)

4、修改像素數組:setPixels(@ColorInt int[] pixels, int offset, int stride, int x, int y, int width, int height)

七、獲取Bitmap

BitmapFactory提供四種方式來獲取Bitmap:文件、資源、字節數組、輸入流。

1、從文件獲取:decodeFile(String pathName, Options opts)

2、從資源獲取:decodeResource(Resources res, int id, Options opts)

3、從字節數組獲取:decodeByteArray(byte[] data, int offset, int length, Options opts)

4、從輸入流獲取:decodeStream(InputStream is, Rect outPadding, Options opts)

--------------------------------------------------------Bitmap進階與擴展----------------------------------------------------------

八、Bitmap與Mat轉換

openCV的圖像處理開發中,操作對象是Mat,而我們Android平臺是Bitmap。這時候就需要Bitmap與Mat的互相轉換了,需要用到Android平臺的openCV SDK,使用Utils類提供的方法來轉換。

1、Bitmap轉Mat:Utils.bitmapToMat(bitmap, mat);

2、Mat轉Bitmap:Utils.matToBitmap(mat, newBitmap);

九:孿生兄弟mipmap

mipmap使用紋理映射技術,壓縮率比bitmap高一倍,所佔內存比bitmap少一半。在Android開發中,Google官方建議Launcher的icon圖標保存在mipmap文件夾下。Bitmap類也提供方法判斷是否支持mipmap:boolean hasMipMap()。

十、圖片解碼爲Bitmap

Android API 28以後,提供ImageDecoder類,可以把編碼的圖片解碼爲Bitmap或Drawable,其中支持的圖片格式有:PNG、JPEG、WEBP、GIF、HEIF。這個類的功能有點類似BitmapFactory,同樣是把圖片轉爲Bitmap。然鵝ImageDecoder功能比較強大。除了解碼圖片,還支持解碼圖片頭信息監聽回調、圖片剪裁、設置圖片分辨率等等。首先看下圖片解碼操作:

@TargetApi(28)
private void decodeImage(){
    ImageDecoder.Source source = ImageDecoder.createSource(getResources(), R.drawable.ferrari);
    try {
        Bitmap bitmap = ImageDecoder.decodeBitmap(source);
        imgDecode.setImageBitmap(bitmap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

如果要實現解碼時,對圖片頭信息監聽,可以使用OnHeaderDecodedListener來回調,其中info包含圖片寬和高。操作如下:

private void decodeImage(){
    ImageDecoder.Source source = ImageDecoder.createSource(getResources(), R.drawable.ferrari);
    try {
        //使用OnHeaderDecodedListener監聽解碼信息
        Bitmap bitmap = ImageDecoder.decodeBitmap(source, new ImageDecoder.OnHeaderDecodedListener() {
            @Override
            public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, ImageDecoder.Source source) {
                Log.e("onHeaderDecoded", "width&&height="+info.getSize());
            }
        });
        imgDecode.setImageBitmap(bitmap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

如果要剪裁,可以在OnHeaderDecodedListener回調中,調用setCrop方法對圖片剪裁:

@TargetApi(28)
private ImageDecoder.OnHeaderDecodedListener headerDecodedListener = new ImageDecoder.OnHeaderDecodedListener() {
    @Override
    public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, ImageDecoder.Source source) {
        //剪裁圖片
        decoder.setCrop(new Rect(0, 0, 300, 200));
    }
};

如果要重新設置分辨率,同樣地,可以在OnHeaderDecodedListener回調中,調用setTargetSize(int width, int height)或者setTargetSampleSize(int sampleSize)來設置。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章