一、Bitmap簡介
Bitmap是位圖文件尽棕,擴(kuò)展名可以是.bmp或者.dib喳挑。
位圖是Windows標(biāo)準(zhǔn)格式圖形文件,它將圖像定義為由點(像素)組成滔悉,每個點可以由多種色彩表示伊诵,包括2,4氧敢,8日戈,16,24和32位色彩孙乖。
位圖文件的圖像效果好浙炼,但是是非壓縮格式的,需要占用較大存儲空間唯袄,不利于在網(wǎng)絡(luò)上傳送弯屈。jpg/png格式恰好彌補(bǔ)了位圖文件的缺點。
二恋拷、字節(jié)換算
計算機(jī)中的信息都是二進(jìn)制的0和1來表示资厉,其中每一個0或1都被稱為一個位,容量是B表示字節(jié)Byte蔬顾,傳輸速度是b表示bit(位)宴偿;
K-千 M-兆 G-吉咖 T-太拉
8bit(位)=1Byte(字節(jié))-->1B=8b
1024字節(jié)(1024B=1024Byte) --》一千字節(jié)(1KB)
1024千字節(jié)(1024 KB)--》一兆字節(jié)(1MB)
1024兆字節(jié)(1024MB)--》一吉字節(jié)(1GB)
1024吉字節(jié)(1024GB)--》一太字節(jié)(1TB)
Kb:千個位
KB:千個字節(jié),一般用來表示文件的大小單位
bps(b/s)是bits per second的縮寫诀豁,表示比特/秒
1KB=1024B=1024*8b
1kB=1000B=8000b
1Kb=1kb=1000b
k代表kilo窄刘,千的意思,也就是1000舷胜,而B就是字節(jié)的意思娩践,ps就是每秒的意思,那么連起來Bps是byte per second的縮寫烹骨,表示字節(jié)/秒翻伺;那kBps就是1000Bps就是一千字節(jié)每秒;
三沮焕、Bitmap計算
圖片是由像素組成的吨岭,要計算一張圖片的大小,需要知道3個參數(shù):圖片的長峦树,圖片的寬未妹,每個像素占用的內(nèi)存大小簿废。
3.1計算公式
圖片占用的內(nèi)存大小=圖片長x圖片寬x每個像素占用的內(nèi)存大小
API在19(包括)以上的使用bitmap.getAllocationByteCount()(返回byte)
API在12(包括)以上的使用
bitmap.getByteCount()(返回byte)
更低版本的使用
bitmap.getRowBytes() * bitmap.getHeight()(返回byte)
3.1.1 每個像素占用的內(nèi)存大小
Android中,每個像素占用的內(nèi)存大小是由Bitmap.Config來決定的络它,它有4中配置:
ARGB_8888:ARGB分別代表的是透明度,紅色,綠色,藍(lán)色,每個值分別用8bit來記錄,也就是一個像素會占用4byte,共32bit.
ARGB_4444:ARGB的是每個值分別用4bit來記錄,一個像素會占用2byte,共16bit.
RGB_565:R=5bit,G=6bit,B=5bit族檬,不存在透明度,每個像素會占用2byte,共16bit.
ALPHA_8:該像素只保存透明度,會占用1byte,共8bit.
在實際應(yīng)用中而言,建議使用ARGB_8888以及RGB_565。
如果你不需要透明度,那么就選擇RGB_565,可以減少一半的內(nèi)存占用.
影響B(tài)itmapFactory.decodeStream()生成的Bitmap的大小是Bitmap.Config化戳,Bitmap.Config不同单料,讀取出來的大小也不一樣。
例如:
一張圖片在windows中看到圖片文件大小是102k(這是壓縮之后的文件)点楼;通過BitmapFactory.decodeStream()方法轉(zhuǎn)成bitmap卻要分配750k的內(nèi)存(因為此時將壓縮文件解壓成內(nèi)存中的bitmap文件扫尖,這是適合顯示的格式,解壓之后掠廓,圖像所占空間變大)换怖;直接用FileOutputStream把inputStream寫入文件,文件大小是102k(這是將文件讀到內(nèi)存中蟀瞧,沒有做解碼操作沉颂,有原樣寫文件,所以大小也沒有變化)
四悦污、Bitmap回收
在安卓3.0以前Bitmap是存放在堆中的铸屉,我們只要回收堆內(nèi)存即可
在安卓3.0以后Bitmap是存放在內(nèi)存中的,我們需要回收native層和Java層的內(nèi)存
官方建議我們3.0以后使用recycle方法進(jìn)行回收切端,該方法也可以不主動調(diào)用彻坛,因為垃圾回收器會自動收集不可用的Bitmap對象進(jìn)行回收
recycle方法會判斷Bitmap在不可用的情況下,將發(fā)送指令到垃圾回收器踏枣,讓其回收native層和Java層的內(nèi)存昌屉,則Bitmap進(jìn)入dead狀態(tài)
recycle方法是不可逆的,如果再次調(diào)用getPixels()等方法茵瀑,則獲取不到想要的結(jié)果
五间驮、壓縮
圖片有三種存在形式:硬盤上是file,網(wǎng)絡(luò)傳輸是stream瘾婿,內(nèi)存中是stream或bitmap
bitmap:Android系統(tǒng)中的圖像格式蜻牢,通常只在內(nèi)存中存在烤咧,系統(tǒng)用于顯示圖像偏陪。bitmap是沒有壓縮的圖像,適合顯示煮嫌,不適合存儲笛谦,因為占用餓過多的存儲空間。
文件:存在硬盤/flash上的文件昌阿,通常是使用了某種壓縮方式饥脑,如jpeg/png恳邀。jpeg進(jìn)行了壓縮,適合存儲灶轰,不能直接顯示谣沸,需要解碼之后才能顯示。
5.1壓縮分類
圖片壓縮分為尺寸壓縮和質(zhì)量壓縮
5.1.1尺寸壓縮(采樣率壓縮)
減小了圖片的像素笋颤,所以它直接對bitmap產(chǎn)生了影響乳附,最終的file也是相對的變小了。主要影響內(nèi)存伴澄。
inSampleSize表示縮略圖大小為原始圖片大小的幾分之一赋除,即如果這個值為2,則取出的縮略圖的寬和高都是原始圖片的1/2非凌, 圖片大小就為原始大小的1/4
5.1.2質(zhì)量壓縮
原理:在保持像素的前提下改變圖片的位深及透明度等举农,來達(dá)到壓縮圖片的目的,bitmap圖片的大小不會改變敞嗡,bytes.length是隨著quality變小而變小的颁糟。
質(zhì)量只對file有影響,可以把一個file轉(zhuǎn)成bitmap在轉(zhuǎn)成file秸妥,或者直接將一個bitmap轉(zhuǎn)成file滚停,這個最終的file是被壓縮過的,但是中間的bitmap并沒有被壓縮(或者說幾乎沒有被壓縮);
因為bitmap在內(nèi)存中的大小是按像素點計算的粥惧,也就是width*height键畴,對于質(zhì)量壓縮,并不會改變圖片的像素突雪,所以就算質(zhì)量被壓縮起惕,但是bitmap在內(nèi)存的占有率還是沒變小,但是變成file時咏删,它確實變小了惹想。
這樣適合去傳遞二進(jìn)制的圖片數(shù)據(jù)。
5.2壓縮代碼
/**
* 質(zhì)量壓縮督函,一直到小于maxsize
*/
public static Bitmap qualityCompressImage(Bitmap image, int maxSize) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//質(zhì)量壓縮方法嘀粱,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
if (image == null) {
return null;
}
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
//循環(huán)判斷如果壓縮后圖片是否大于maxSizekb,大于繼續(xù)壓縮
while (baos.toByteArray().length / 1024 > maxSize) {
//重置baos即清空baos
baos.reset();
//這里壓縮options%辰狡,把壓縮后的數(shù)據(jù)存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
options -= 10;
if (options < 0) {
break;
}
}
//把壓縮后的數(shù)據(jù)baos存放到ByteArrayInputStream中
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
//把ByteArrayInputStream數(shù)據(jù)生成圖片
return BitmapFactory.decodeStream(isBm);
}
/**
* 圖片按比例大小壓縮方法
*
* @param image (根據(jù)Bitmap圖片壓縮)
* @return
*/
public static Bitmap compressScale(Bitmap image, int maxSize) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
// 判斷如果圖片大于1M,進(jìn)行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢出
if (baos.toByteArray().length / 1024 > 1024) {
// 重置baos即清空baos
baos.reset();
// 這里壓縮80%锋叨,把壓縮后的數(shù)據(jù)存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, 80, baos);
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 開始讀入圖片,此時把options.inJustDecodeBounds 設(shè)回true
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);//此時bitmap返回空宛篇,可以避免bitmap的內(nèi)存分配只拿到bitmap的寬高及MimeType
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
float hh = 800f;
float ww = 480f;
// 縮放比娃磺。由于是固定比例縮放,只用高或者寬其中一個數(shù)據(jù)進(jìn)行計算即可
// be=1表示不縮放
int be = 1;
// 如果寬度大的話根據(jù)寬度固定大小縮放
if (w > h && w > ww) {
be = Math.round((float) newOpts.outWidth / ww);
// 如果高度高的話根據(jù)高度固定大小縮放
} else if (w < h && h > hh) {
be = Math.round((float) newOpts.outHeight / hh);
}
if (be <= 0) {
be = 1;
}
// 設(shè)置縮放比例
newOpts.inSampleSize = be;//寬高都為原來的1/be
// newOpts.inPreferredConfig = Config.RGB_565;//降低圖片從ARGB888到RGB565
// 重新讀入圖片叫倍,注意此時已經(jīng)把options.inJustDecodeBounds 設(shè)回false了
isBm = new ByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
// 壓縮好比例大小后再進(jìn)行質(zhì)量壓縮
return qualityCompressImage(bitmap, maxSize);
}
參考:
(12條消息) android 根據(jù)圖片url獲取bitmap或者drawable偷卧,然后再進(jìn)行壓縮處理_碼在飛博客-CSDN博客
Android中的Bitmap的詳細(xì)介紹Android腳本之家 (jb51.net)