Bitmap學習(大圖片痴鳄、大長圖顯示及加載)

前幾天公司項目出現(xiàn)一個需求昆著,加載網(wǎng)絡大長圖县貌,搜索了一些方法,最終是將圖片下載到本地凑懂,然后通過BitmapRegionDecode.newInstance(...)獲取一個對象煤痕,然后通過這個對象去調用decodeRegion(mRect, options)得到bitmap,用手勢控制圖片顯示的區(qū)域接谨。解決辦法的原理就是這樣摆碉,可是實現(xiàn)起來確實遇到了很多問題,而且晚上也沒有很完整的方法脓豪,基本都是參照張鴻洋大神的本地加載大圖片方法巷帝,網(wǎng)絡加載有些不太適用,而且我的場景是在recyclerview的item中的imageview跑揉。所以走了很多彎路。我這里就順便復習一下bitmap

1.Bitmap的概念:

Android中的Bitmap對象是對位圖的抽象埠巨,它可以從文件系統(tǒng)历谍、資源文件夾、網(wǎng)絡等各種不同的來源獲取辣垒。位圖可以看做是像素點的集合望侈,本質上就是通過一系列二進制位來描述一張圖片,具有不同色彩格式的位圖使用不同數(shù)量的二進制位來描述一個像素點勋桶,因而圖片質量和圖片大小也就不同脱衙。

獲取Bitmap對象并計算它所占用的內存大薪拟:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.size);
int size = bitmap.getByteCount();

getByteCount()源碼:

public final int getByteCount() {
    return getRowBytes() * getHeight();
}

getHeight():圖片的高度(單位為px), getRowBytes方法返回的是圖片的像素寬度與色彩深度的乘積。
所以getByteCount()是這樣計算的:像素寬 * 像素高 * 色彩深度捐韩,其中色彩深度與Bitmap的色彩格式有關退唠,默認為ARGB_8888.

這里補充一個小知識點吧!

ARGB_4444: 2bytes 每個像素占據(jù)2 個字節(jié):A(Alpha)占4位的精度荤胁,R(Red)占4位的精度瞧预,G(Green)占4位的精度,B(Blue)占4位的精度仅政,加起來一共是16位的精度垢油,折合是2個字節(jié),也就是一個像素占兩個字節(jié)的內存圆丹,同時存儲位圖的透明度和顏色信息滩愁。

ARGB_8888 : 4bytes 每個像素占據(jù)4 個字節(jié):這個類型的跟ARGB_4444的原理是一樣的,只是A,R,G,B各占8個位的精度辫封,所以一個像素占4個字節(jié)的內存硝枉。由于該類型的位圖質量較好,官方特別推薦使用秸讹。但是檀咙,如果一個480800的位圖設置了此類型,那個它占用的內存空間是:4808004/(10241024)=1.5M

RGB_565 : 2bytes 每個像素占據(jù)2 個字節(jié):R占5位精度璃诀,G占6位精度弧可,B占5位精度,一共是16位精度劣欢,折合兩個字節(jié)棕诵。這里注意的時,這個類型存儲的只是顏色信息凿将,沒有透明度信息

2.構造Bitmap對象

構造一個類校套,通常都是通過構造器方法,然而Bitmap是采用了工廠的設計模式牧抵,所以一般不會直接調用構造方法笛匙。

1.createBitmap(不建議)

圖一

2.BitmapFactory工廠類的static Bitmap decodeXxx()系

圖二

注意,圖片的基本加載既不是本文的重點犀变,也不是什么難點妹孙,所以這里就不貼詳細代碼,提示一句获枝,有些方法需要在子線程中

3.高效的加載Bitmap

在使用bitmap時,經(jīng)常會遇到內存溢出等情況蠢正,這是因為圖片太大或者android系統(tǒng)對單個應用施加的內存限制等原因造成的
常見的錯誤:

OpenGLRenderer: Bitmap too large to be uploaded into a texture

java.lang.OutOfMemoryError:

所以,高效的使用bitmap就顯得尤為重要省店,對他效率的優(yōu)化也是如此嚣崭。

系統(tǒng)為我們提供了Options類,通過對它的options進行合理的配置笨触,我們就能夠將Bitmap對象調整到令我們滿意的大小。

3.1.Options類介紹

public static class Options {
    public Options() {
        inDither = false;
        inScaled = true;
        inPremultiplied = true;
    }
...      
    public Bitmap inBitmap; //用于實現(xiàn)Bitmap的復用雹舀,下面會具體介紹
    public int inSampleSize;  //采樣率 
    public boolean inPremultiplied;   
    public boolean inDither;  //是否開啟抖動
    public int inDensity; //即上文我們提到的inDensity
    public int inTargetDensity;  //目標屏幕密度芦劣,同上文提到的含義相同            
    public boolean inScaled;    //是否支持縮放
    public int outWidth;   //圖片的原始寬度
    public int outHeight;  //圖片的原始高度
...
}

上面代碼是Options類的主要成員變量,我通過對大圖片的處理方式去做具體講解吧葱跋!

1>尺寸壓縮(采樣率壓縮)bitmap.inSampleSize

尺寸壓縮是壓縮圖片的像素持寄,一張圖片所占內存的大小 圖片類型*寬*高,通過改變三個值減小圖片所占的內存娱俺,防止OOM稍味,當然這種方式可能會使圖片失真 。

第一步荠卷,獲取圖片的原始寬高模庐,通過將Options的inJustDecodeBounds屬性設為true后調用decodeXXX方法,BitmapFactory只會解析圖片的原始寬高信息油宜,并不會真正的加載圖片掂碱,請看以下代碼:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), resId, options);
//現(xiàn)在原始寬高以存儲在了options對象的outWidth和outHeight實例域中

第二步,根據(jù)原始寬高計算出inSampleSize慎冤,代碼如下:

//dstWidth和dstHeight分別為目標ImageView的寬高
public static int calSampleSize(BitmapFactory.Options options, int dstWidth, int    dstHeight) {
    int rawWidth = options.outWidth;
    int rawHeight = options.outHeight;
    int inSampleSize = 1;
    if (rawWidth > dstWidth || rawHeight > dstHeight) {
    float ratioHeight = (float) rawHeight / dstHeight;
    float ratioWidth = (float) rawWidth / dstHeight;
    inSampleSize = (int) Math.min(ratioWidth, ratioHeight);
    }
    return inSampleSize;
}

第三步疼燥,將BitmapFacpry.Options的inSampleSize參數(shù)設為false并重新加載圖片

options.inJustDecodeBounds =false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId, options);

這樣就可以實現(xiàn)圖片尺寸的壓縮

2>質量壓縮bitmap.compress

質量壓縮是在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的蚁堤,經(jīng)過它壓縮的圖片文件大小(kb)會有改變醉者,但是導入成bitmap后占得內存是不變的,寬高也不會改變披诗。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法撬即,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
int options = 90;
int bytes = baos.toByteArray().length;
while ((bytes / 1024 > 500) && (options >= 20)) {  //循環(huán)判斷如果壓縮后圖片是否大于500kb,大于繼續(xù)壓縮
   baos.reset();//重置baos即清空baos
   options -= 10;//每次都減少10
   //第一個參數(shù) :圖片格式 呈队,第二個參數(shù): 圖片質量剥槐,100為最高,0為最差  宪摧,第三個參數(shù):保存壓縮后的數(shù)據(jù)的流
   image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這里壓縮options%粒竖,把壓縮后的數(shù)據(jù)存放到baos中
   bytes = baos.toByteArray().length;
}
image.recycle();
圖三

可以看到,圖片的大小是沒有變的几于,因為質量壓縮不會減少圖片的像素蕊苗,它是在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的孩革,這也是為什么該方法叫質量壓縮方法岁歉。那么得运,圖片的長膝蜈,寬锅移,像素都不變,那么bitmap所占內存大小是不會變的饱搏。

Bitmap.compress方法確實可以壓縮圖片非剃,但壓縮的是存儲大小,即你放到disk上的大小

3>縮放法壓縮 martix

Matrix matrix = new Matrix();
        matrix.setScale(0.5f, 0.5f);
        bm = Bitmap.createBitmap(bit, 0, 0, bit.getWidth(),
                bit.getHeight(), matrix, true);
        Log.i("wechat", "壓縮后圖片的大小" + (bm.getByteCount() / 1024 / 1024)
                + "M寬度為" + bm.getWidth() + "高度為" + bm.getHeight());

以上三種方法適用場景:大圖片上傳推沸,一般是1备绽,2方法結合使用,網(wǎng)上有很多最優(yōu)算法鬓催,但是實現(xiàn)思路不變肺素,下面再說說大圖片顯示問題

3.2.BitmapRegionDecoder類介紹

BitmapRegionDecoder類用來編譯(解碼)在圖片內不同的方形區(qū)域,BitmapRegionDecoder類在使用較大圖片只需要取得圖片中的一小部分的內容是特別有效益的宇驾。

我們創(chuàng)建一個BitmapRegionDecoder類倍靡,并調用newInstace()方法,就可以得到BitmapRegionDecoder的對象之后课舍,我們就能調用decodeRegion()方法去多次獲得位圖的特定地區(qū)的小圖片

1>BitmapRegionDecoder的創(chuàng)建

public static BitmapRegionDecoder newInstance (String pathName, boolean isShareable)

用于創(chuàng)建BitmapRegionDecoder塌西,pathName表示路徑,只有jpeg和png圖片才支持這種方式筝尾,isShareable如果為true捡需,那BitmapRegionDecoder會對輸入流保持一個表面的引用,如果為false筹淫,那么它將會創(chuàng)建一個輸入流的復制站辉,并且一直使用它。即使為true贸街,程序也有可能會創(chuàng)建一個輸入流的深度復制庵寞。如果圖片是逐步解碼的,那么為true會降低圖片的解碼速度薛匪。如果路徑下的圖片不是支持的格式捐川,那就會拋出異常

public static BitmapRegionDecoder newInstance (InputStream is, boolean isShareable)

同上,不過參數(shù)is變成了輸入流

public static BitmapRegionDecoder newInstance (FileDescriptor fd, boolean isShareable)

同上逸尖,不過參數(shù)變成了文件描述符古沥,在函數(shù)運行完之前,文件描述符不可以改變

public static BitmapRegionDecoder newInstance (byte[] data, int offset, int length, boolean isShareable)

同上娇跟,不過參數(shù)變成了字節(jié)數(shù)組岩齿,offset為起始位置,length為長度

2>BitmapRegionDecoder的解碼區(qū)域

public Bitmap decodeRegion (Rect rect, BitmapFactory.Options options)

參數(shù)一很明顯是一個rect苞俘,參數(shù)二是BitmapFactory.Options盹沈,可以控制圖片的inSampleSize,inPreferredConfig等。

本地加載大圖片吃谣,我之前分享過一篇文章:

http://www.reibang.com/p/5a250b68c331

網(wǎng)絡加載大圖片乞封,思路差不多做裙,但是需要先下載到本地再進行一系列操作,具體代碼肃晚,就不展示了锚贱,可以提供個github庫,大家看一看就應該懂了:

compile 'com.shizhefei:LargeImageView:1.0.9'

因為是公司項目关串,所以暫時不方便展示具體代碼拧廊,后期抽時間提煉出來個demo貼出來。晋修。吧碾。

到這里其實就差不多了。墓卦。滤港。記得點贊
謝謝閱讀,我這里也是學習的態(tài)度在這里分享趴拧,有什么問題希望大家能提出來能提出來溅漾,隨時可以和我交流探討:QQ:707086125 微信:loveme_dp

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市著榴,隨后出現(xiàn)的幾起案子添履,更是在濱河造成了極大的恐慌,老刑警劉巖脑又,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暮胧,死亡現(xiàn)場離奇詭異,居然都是意外死亡问麸,警方通過查閱死者的電腦和手機往衷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來严卖,“玉大人席舍,你說我怎么就攤上這事∠剩” “怎么了来颤?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長稠肘。 經(jīng)常有香客問我福铅,道長,這世上最難降的妖魔是什么项阴? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任滑黔,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘略荡。我一直安慰自己色查,他們只是感情好,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布撞芍。 她就那樣靜靜地躺著,像睡著了一般跨扮。 火紅的嫁衣襯著肌膚如雪序无。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天衡创,我揣著相機與錄音帝嗡,去河邊找鬼。 笑死璃氢,一個胖子當著我的面吹牛哟玷,可吹牛的內容都是我干的。 我是一名探鬼主播一也,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼巢寡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了椰苟?” 一聲冷哼從身側響起抑月,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤隧魄,失蹤者是張志新(化名)和其女友劉穎输拇,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體紧显,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡洁仗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年层皱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赠潦。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡叫胖,死狀恐怖,靈堂內的尸體忽然破棺而出她奥,到底是詐尸還是另有隱情臭家,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布方淤,位于F島的核電站钉赁,受9級特大地震影響,放射性物質發(fā)生泄漏携茂。R本人自食惡果不足惜你踩,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧带膜,春花似錦吩谦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芭挽,卻和暖如春滑废,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袜爪。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工蠕趁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辛馆。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓俺陋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昙篙。 傳聞我的和親對象是個殘疾皇子腊状,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內容