程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 有效地加載大尺寸位圖(Loading Large Bitmaps Efficiently)

有效地加載大尺寸位圖(Loading Large Bitmaps Efficiently)

編輯:關於C++

有效地加載大尺寸位圖(Loading Large Bitmaps Efficiently)

圖片有不同的形狀與大小。在大多數情況下它們的實際大小都比需要呈現出來的要大很多。例如,系統的Gallery程序會顯示那些你使用設備camera拍攝的圖片,但是那些圖片的分辨率通常都比你的設備屏幕分辨率要高很多。

考慮到程序是在有限的內存下工作,理想情況是你只需要在內存中加載一個低分辨率的版本即可。這個低分辨率的版本應該是與你的UI大小所匹配的,這樣才便於顯示。一個高分辨率的圖片不會提供任何可見的好處,卻會占用寶貴的(precious)的內存資源,並且會在快速滑動圖片時導致(incurs)附加的效率問題。

這一課會介紹如何通過加載一個縮小版本的圖片到內存中去decoding大的bitmaps,從而避免超出程序的內存限制。

讀取位圖的尺寸與類型(Read Bitmap Dimensions and Type)

BitmapFactory 類提供了一些decode的方法 (decodeByteArray(), decodeFile(), decodeResource(), etc.) 用來從不同的資源中創建一個Bitmap. 根據你的圖片數據源來選擇合適的decode方法. 那些方法在構造位圖的時候會嘗試分配內存,因此會容易導致OutOfMemory的異常。每一種decode方法都提供了通過BitmapFactory.Options 來設置一些附加的標記來指定decode的選項。設置 inJustDecodeBounds 屬性為true可以在decoding的時候避免內存的分配,它會返回一個null的bitmap,但是 outWidth, outHeight 與 outMimeType 還是可以獲取。這個技術可以允許你在構造bitmap之前優先讀圖片的尺寸與類型。

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

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

int imageWidth = options.outWidth;

String imageType = options.outMimeType;

為了避免java.lang.OutOfMemory 的異常,我們需要在真正decode圖片之前檢查它的尺寸,除非你確定這個數據源提供了准確無誤的圖片且不會導致占用過多的內存。

加載一個按比例縮小的版本到內存中(Load a Scaled Down Version into Memory)

通過上面的步驟我們已經知道了圖片的尺寸,那些數據可以用來決定是應該加載整個圖片到內存中還是加載一個縮小的版本。有下面一些因素需要考慮:

評估加載完整圖片所需要耗費的內存。

程序在加載這張圖片時會涉及到其他內存需求。

呈現這張圖片的組件的尺寸大小。

屏幕大小與當前設備的屏幕密度。

例如,如果把一個原圖是1024*768 pixel的圖片顯示到ImageView為128*96 pixel的縮略圖就沒有必要把整張圖片都加載到內存中。

為了告訴decoder去加載一個低版本的圖片到內存,需要在你的BitmapFactory.Options 中設置 inSampleSize 為 true 。For example, 一個分辨率為2048x1536 的圖片,如果設置 inSampleSize 為4,那麼會產出一個大概為512x384的bitmap。加載這張小的圖片僅僅使用大概0.75MB,如果是加載全圖那麼大概要花費12MB(前提都是bitmap的配置是 ARGB_8888). 下面有一段根據目標圖片大小來計算Sample圖片大小的Sample Code:

public static int calculateInSampleSize(

BitmapFactory.Options options, int reqWidth, int reqHeight) {

// Raw height and width of image

final int height = options.outHeight;

final int width = options.outWidth;

int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

final int halfHeight = height / 2;

final int halfWidth = width / 2;

// Calculate the largest inSampleSize value that is a power of 2 and keeps both

// height and width larger than the requested height and width.

while ((halfHeight / inSampleSize) > reqHeight

&& (halfWidth / inSampleSize) > reqWidth) {

inSampleSize *= 2;

}

}

return inSampleSize;

}

Note: 設置inSampleSize為2的冪是因為decoder最終還是會對非2的冪的數進行向下處理,獲取到最靠近2的冪的數。詳情參考inSampleSize的文檔。

為了使用這個方法,首先需要設置 inJustDecodeBounds 為 true, 把options的值傳遞過來,然後使用 inSampleSize 的值並設置 inJustDecodeBounds 為 false 來重新Decode一遍。

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,

int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions

final BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set

options.inJustDecodeBounds = false;

return BitmapFactory.decodeResource(res, resId, options);

}

使用上面這個方法可以簡單的加載一個任意大小的圖片並顯示為100*100 pixel的縮略圖形式。像下面演示的一樣:

mImageView.setImageBitmap(

decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

你可以通過替換合適的BitmapFactory.decode* 方法來寫一個類似的方法從其他的數據源進行decode bitmap。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved