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)來設置。