圖片壓縮跪楞,二次采樣

圖片壓縮就是為了避免我們內(nèi)存溢出,所有要對一系列進(jìn)行壓縮二次采樣等

1.什么是OOM堡赔?為什么會引起OOM识脆?

out of Memory(內(nèi)存溢出)我們都知道Android系統(tǒng)會被每個App分配一個獨(dú)立的空間,或者說分配一個Dalvik虛擬機(jī)(Dalvik是Google公司自己設(shè)計用于Android平臺的虛擬機(jī)善已。Dalvik虛擬機(jī)是Google等廠商合作開發(fā)的Android移動設(shè)備平臺的核心組成部分之一灼捂。它可以支持已轉(zhuǎn)換為 .dex(即Dalvik Executable)格式的Java應(yīng)用程序的運(yùn)行,.dex格式是專為Dalvik設(shè)計的一種壓縮格式换团,適合內(nèi)存和處理器速度有限的系統(tǒng)悉稠。Dalvik經(jīng)過優(yōu)化,允許在有限的內(nèi)存中同時運(yùn)行多個虛擬機(jī)的實例艘包,并且[1]每一個Dalvik應(yīng)用作為一個獨(dú)立的Linux 進(jìn)程執(zhí)行的猛。獨(dú)立的進(jìn)程可以防止在虛擬機(jī)崩潰的時候所有程序都被關(guān)閉。)這樣每個APP都可以獨(dú)立運(yùn)行而不相互影響想虎!而Android對于每個 Dalvik虛擬機(jī)都會有一個最大內(nèi)存限制卦尊,如果當(dāng)前占用的內(nèi)存加上我們申請的內(nèi)存資源超過了這個限制 ,系統(tǒng)就會拋出OOM錯誤舌厨!另外岂却,這里別和RAM混淆了,即時當(dāng)前RAM中剩余的內(nèi)存有1G多邓线,但是OOM還是會發(fā)生淌友!別把RAM(物理內(nèi)存)和OOM扯到一起!另外RAM不足的話骇陈,就是殺應(yīng)用了震庭,而不是僅僅是OOM了! 而這個Dalvik中的最大內(nèi)存標(biāo)準(zhǔn)你雌,不同的機(jī)型是不一樣的


這里可以獲取系統(tǒng)分給你App多少內(nèi)存

ActivityManager?activityManager =?(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);?Log.e("HEHE","最大內(nèi)存:"?+?activityManager.getMemoryClass());


一器联、Bitmap:

Bitmap是Android系統(tǒng)中的圖像處理的最重要類之一二汛。用它可以獲取圖像文件信息,進(jìn)行圖像剪切拨拓、旋轉(zhuǎn)肴颊、縮放等操作,并可以指定格式保存圖像文件渣磷。

常用方法:

public void recycle()  // 回收位圖占用的內(nèi)存空間婿着,把位圖標(biāo)記為Dead

public final boolean isRecycled()  //判斷位圖內(nèi)存是否已釋放

public final int getWidth() //獲取位圖的寬度

public final int getHeight() //獲取位圖的高度

public final boolean isMutable() //圖片是否可修改

public int getScaledWidth(Canvas canvas) //獲取指定密度轉(zhuǎn)換后的圖像的度

public int getScaledHeight(Canvas canvas) //獲取指定密度轉(zhuǎn)換后的圖像的度

public boolean compress(CompressFormat format, int quality, OutputStream stream) //按指定的圖片格式以及畫質(zhì),將圖片轉(zhuǎn)換為輸出流醋界。

format:壓縮圖像的格式,如Bitmap.CompressFormat.PNG或 ·Bitmap.CompressFormat.JPEG

quality:畫質(zhì)竟宋,0-100.0表示最低畫質(zhì)壓縮,100以最高畫質(zhì)壓縮形纺。對于PNG等無損格式的圖片丘侠,會忽略此項設(shè)置。

stream: OutputStream中寫入壓縮數(shù)據(jù)逐样。

return: 是否成功壓縮到指定的流蜗字。

public static Bitmap createBitmap(Bitmap src)  //以src為原圖生成不可變得新圖像

public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) //以src為原圖,創(chuàng)建新的圖像脂新,指定新圖像的高寬以及是否可變挪捕。

public static Bitmap createBitmap(int width, int height, Config config) //創(chuàng)建指定格式、大小的位圖

public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) //以source為原圖戏羽,創(chuàng)建新的圖片担神,指定起始坐標(biāo)以及新圖像的高寬。

BitmapFactory.Option可設(shè)置參數(shù)

Option 參數(shù)類:

public boolean inJustDecodeBounds //如果設(shè)置為true始花,不獲取圖片妄讯,不分配 內(nèi)存,但會返回圖片的高度寬度信息酷宵。

如果將這個值置為true亥贸,那么在解碼的時候?qū)⒉粫祷豣itmap,只會返回這個bitmap 的尺寸浇垦。這個屬性的目的是炕置,如果你只想知道一個bitmap的尺寸,但又不想將其加載到內(nèi)存時男韧。這是一個非常有用的屬性朴摊。

public int inSampleSize //圖片縮放的倍數(shù)

這個值是一個int,當(dāng)它小于1的時候此虑,將會被當(dāng)做1處理甚纲,如果大于1,那么就會按照比例(1 / inSampleSize)縮小bitmap的寬和高朦前、降低分辨率介杆,大于1時這個值將會被處置為2的倍數(shù)鹃操。例如,width=100春哨,height=100荆隘,inSampleSize=2,那么就會將bitmap處理為赴背,width=50椰拒,height=50,寬高降為1 / 2凰荚,像素數(shù)降為1 / 4耸三。

public int outWidth //獲取圖片的寬度值

public int outHeight //獲取圖片的高度值

表示這個Bitmap的寬和高,一般和inJustDecodeBounds一起使用來獲得Bitmap的寬高浇揩,但是不加載到內(nèi)存。

public int inDensity //用于位圖的像素壓縮比

public int inTargetDensity //用于目標(biāo)位圖的像素壓縮比(要生成的位圖)

public byte[] inTempStorage  //創(chuàng)建臨時文件憨颠,將圖片存儲

public boolean inScaled //設(shè)置為true時進(jìn)行圖片壓縮胳徽,從inDensity到inTargetDensity

public boolean inDither  //如果為true,解碼器嘗試抖動解碼

public Bitmap.Config inPreferredConfig  //設(shè)置解碼器

這個值是設(shè)置色彩模式,默認(rèn)值是ARGB_8888爽彤,在這個模式下养盗,一個像素點(diǎn)占用4bytes空間,一般對透明度不做要求的話适篙,一般采用RGB_565模式往核,這個模式下一個像素點(diǎn)占用2bytes。

public String outMimeType  //設(shè)置解碼圖像

public boolean inPurgeable //當(dāng)存儲Pixel的內(nèi)存空間在系統(tǒng)內(nèi)存不足時是否可以被回收

public boolean inInputShareable  //inPurgeable為true情況下才生效嚷节,是否可以共享一個InputStream

public boolean inPreferQualityOverSpeed  //為true則優(yōu)先保證Bitmap質(zhì)量其次是解碼速度

public boolean inMutable  //配置Bitmap是否可以更改聂儒,比如:在Bitmap上隔幾個像素加一條線段

public int inScreenDensity  //當(dāng)前屏幕的像素密度

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

你可以創(chuàng)建一個構(gòu)造一個BitmapDrawable對象,比如通過流構(gòu)建BitmapDrawable:

BitmapDrawable?bmpMeizi =?new?BitmapDrawable(getAssets().open("pic_meizi.jpg"));?Bitmap?mBitmap =?bmpMeizi.getBitmap();?img_bg.setImageBitmap(mBitmap);


工廠方法:

public static Bitmap decodeFile(String pathName, Options opts)  //從文件讀取圖片

public static Bitmap decodeFile(String pathName)

public static Bitmap decodeStream(InputStream is)  //從輸入流讀取圖片

public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts)

public static Bitmap decodeResource(Resources res, int id)  //從資源文件讀取圖片

public static Bitmap decodeResource(Resources res, int id, Options opts)

public static Bitmap decodeByteArray(byte[] data, int offset, int length)  //從數(shù)組讀取圖片

public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts)

public static Bitmap decodeFileDescriptor(FileDescriptor fd) //從文件讀取文件 與decodeFile不同的是這個直接調(diào)用JNI函數(shù)進(jìn)行讀取 效率比較高

public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)

首先了解一下關(guān)于Bitmap的Config的理解

A:透明度 R:紅色 G:綠 B:藍(lán)

Bitmap.Config ARGB_4444:每個像素占四位硫痰,即A=4衩婚,R=4,G=4效斑,B=4非春,那么一個像素點(diǎn)占4+4+4+4=16位

Bitmap.Config ARGB_8888:每個像素占四位,即A=8缓屠,R=8奇昙,G=8,B=8敌完,那么一個像素點(diǎn)占8+8+8+8=32位

Bitmap.Config RGB_565:每個像素占四位储耐,即R=5,G=6蠢挡,B=5弧岳,沒有透明度凳忙,那么一個像素點(diǎn)占5+6+5=16位

Bitmap.Config ALPHA_8:每個像素占四位,只有透明度禽炬,沒有顏色涧卵。


bitmap內(nèi)存大小 = 圖片長度 x 圖片寬度 x 單位像素占用的字節(jié)數(shù)

起決定因素就是最后那個參數(shù)了,Bitmap'常見有2種編碼方式:ARGB_8888和RGB_565腹尖,ARGB_8888每個像素點(diǎn)4個byte柳恐,RGB_565是2個byte,一般都采用ARGB_8888這種热幔。那么常見的1080*1920的圖片內(nèi)存占用就是:

1920 x 1080 x 4 = 7.9M


常用的壓縮方法:

1.質(zhì)量壓縮

private void compressQuality() { Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.test); mSrcSize = bm.getByteCount() + "byte"; ByteArrayOutputStream bos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.JPEG, 100, bos); byte[] bytes = bos.toByteArray(); mSrcBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); }

質(zhì)量壓縮不會減少圖片的像素乐设,它是在保持像素的前提下改變圖片的位深及透明度,來達(dá)到壓縮圖片的目的绎巨,圖片的長近尚,寬,像素都不會改變场勤,那么bitmap所占內(nèi)存大小是不會變的戈锻。

我們可以看到有個參數(shù):quality,可以調(diào)節(jié)你壓縮的比例和媳,但是還要注意一點(diǎn)就是格遭,質(zhì)量壓縮堆png格式這種圖片沒有作用,因為png是無損壓縮留瞳。

2.采樣率壓縮

private void compressSampling() { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test, options); }

采樣率壓縮其原理其實也是縮放bitamp的尺寸拒迅,通過調(diào)節(jié)其inSampleSize參數(shù),比如調(diào)節(jié)為2她倘,寬高會為原來的1/2璧微,內(nèi)存變回原來的1/4.

3.放縮法壓縮

private void compressMatrix() { Matrix matrix = new Matrix(); matrix.setScale(0.5f, 0.5f); Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.test); mSrcBitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); bm = null; }

放縮法壓縮使用的是通過矩陣對圖片進(jìn)行裁剪,也是通過縮放圖片尺寸硬梁,來達(dá)到壓縮圖片的效果往毡,和采樣率的原理一樣

4.RGB_565壓縮

private void compressRGB565() { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test, options); }

這是通過壓縮像素占用的內(nèi)存來達(dá)到壓縮的效果潜沦,一般不建議使用ARGB_4444输硝,因為畫質(zhì)實在是辣雞,如果對透明度沒有要求壳澳,建議可以改成RGB_565罩息,相比ARGB_8888將節(jié)省一半的內(nèi)存開銷嗤详。

5.createScaledBitmap

private void compressScaleBitmap() { Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.test); mSrcBitmap = Bitmap.createScaledBitmap(bm, 600, 900, true); bm = null; }

將圖片的大小壓縮成用戶的期望大小,來減少占用內(nèi)存瓷炮。


圖片二次采樣

private Bitmap getCompressBm(int id, int maxw, int maxh) {

Bitmap bm = null;

int iSamplesize = 1;

//第一次采樣

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

//該屬性設(shè)置為true只會加載圖片的邊框進(jìn)來葱色,并不會加載圖片具體的像素點(diǎn)

bitmapFactoryOptions.inJustDecodeBounds = true;

bm = BitmapFactory.decodeResource(getResources(), id, bitmapFactoryOptions);

Log.e("Tag", "onActivityResult: 壓縮之前圖片的寬:" + bitmapFactoryOptions.outWidth + "--壓縮之前圖片的高:"

+ bitmapFactoryOptions.outHeight + "--壓縮之前圖片大小:" + bitmapFactoryOptions.outWidth * bitmapFactoryOptions.outHeight * 4 / 1024 + "kb");

int iWidth = bitmapFactoryOptions.outWidth;

int iHeight = bitmapFactoryOptions.outHeight;

//對縮放比例進(jìn)行調(diào)整,直到寬和高符合我們要求為止

while (iWidth > maxw|| iHeight > maxh){

//如果寬高的任意一方的縮放比例沒有達(dá)到要求娘香,都繼續(xù)增大縮放比例

//sampleSize應(yīng)該為2的n次冪苍狰,如果給sampleSize設(shè)置的數(shù)字不是2的n次冪办龄,那么系統(tǒng)會就近取

iSamplesize = iSamplesize*2;//寬高均為原圖的寬高的1/2 內(nèi)存約為原來的1/4

iWidth = iWidth/iSamplesize;

iHeight = iHeight/iSamplesize;

}

//二次采樣開始

//二次采樣時我需要將圖片加載出來顯示,不能只加載圖片的框架淋昭,因此inJustDecodeBounds屬性要設(shè)置為false

bitmapFactoryOptions.inJustDecodeBounds = false;

bitmapFactoryOptions.inSampleSize = iSamplesize;

// 設(shè)置像素顏色信息

// bitmapFactoryOptions.inPreferredConfig = Bitmap.Config.RGB_565;

bm = BitmapFactory.decodeResource(getResources(),id, bitmapFactoryOptions);

//默認(rèn)的圖片格式是Bitmap.Config.ARGB_8888

Log.e("Tag", "onActivityResult: 圖片的寬:" + bm.getWidth() + "--圖片的高:"

+ bm.getHeight() + "--圖片大小:" + bm.getWidth() * bm.getHeight() * 4 / 1024 + "kb");

return bm;//返回壓縮后的照片

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俐填,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翔忽,更是在濱河造成了極大的恐慌英融,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歇式,死亡現(xiàn)場離奇詭異驶悟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)材失,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門痕鳍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人龙巨,你說我怎么就攤上這事额获。” “怎么了恭应?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耘眨。 經(jīng)常有香客問我昼榛,道長,這世上最難降的妖魔是什么剔难? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任胆屿,我火速辦了婚禮,結(jié)果婚禮上偶宫,老公的妹妹穿的比我還像新娘非迹。我一直安慰自己,他們只是感情好纯趋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布憎兽。 她就那樣靜靜地躺著,像睡著了一般吵冒。 火紅的嫁衣襯著肌膚如雪纯命。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天痹栖,我揣著相機(jī)與錄音亿汞,去河邊找鬼。 笑死揪阿,一個胖子當(dāng)著我的面吹牛疗我,可吹牛的內(nèi)容都是我干的咆畏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吴裤,長吁一口氣:“原來是場噩夢啊……” “哼旧找!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嚼摩,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钦讳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后枕面,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愿卒,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年潮秘,在試婚紗的時候發(fā)現(xiàn)自己被綠了琼开。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡枕荞,死狀恐怖柜候,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情躏精,我是刑警寧澤渣刷,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站矗烛,受9級特大地震影響辅柴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞭吃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一碌嘀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧歪架,春花似錦股冗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至攒霹,卻和暖如春导俘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剔蹋。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工旅薄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓少梁,卻偏偏與公主長得像洛口,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凯沪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容