解決android縮放圖片導致OOM的一個方案

安卓開發中應用到圖片的處理時候,我們通常會怎麼縮放操作呢,來看下面的兩種做法:

  方法1:按固定比例進行縮放

  在開發一些軟件,如新聞客戶端,很多時候要顯示圖片的縮略圖,由於手機屏幕限制,一般情況下,我們取圖片的縮略圖,取縮略圖的方法我們可以使用BitmapFactory的decodeFile方法,然後通過傳遞進去 BitmapFactory.Option類型的參數進行取縮略圖,在Option中,屬性值inSampleSize表示縮略圖大小爲原始圖片大小的幾分之一,即如果這個值爲2,則取出的縮略圖的寬和高都是原始圖片的1/2,圖片大小就爲原始大小的1/4。但是,如果我們想取固定大小的縮略圖就比較困難了,比如,我們想將不同大小的圖片取出來的縮略圖高度都爲200px,同時要保證圖片不失真,那我們該怎麼辦?總不能將原始圖片加載到內存中再進行縮放處理吧,要知道在移動開發中,內存是相當寶貴的,一張100K的圖片,加載完所佔用的內存何止是100K。

經過閱讀文檔發現,Options中有個屬性inJustDecodeBounds,文檔中的是這麼說的:

  If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.  意思就是說如果該值設爲true那麼將不返回實際的bitmap對象,不給其分配內存空間但是可以得到一些解碼邊界信息即圖片大小等信息。因此我們可以通過設置inJustDecodeBounds爲true,獲取到outHeight(圖片原始高度)和 outWidth(圖片的原始寬度),然後計算一個inSampleSize(縮放值),就可以取圖片了,這裏要注意的是,inSampleSize 可能等於0,必須做判斷。也就是說先將Options的屬性inJustDecodeBounds設爲true,先獲取圖片的基本大小信息數據(信息沒有保存在bitmap裏面,而是保存在options裏面),通過options.outHeight和 options. outWidth獲取的大小信息以及自己想要到得圖片大小計算出來縮放比例inSampleSize,然後緊接着將inJustDecodeBounds設爲false,就可以根據已經得到的縮放比例得到自己想要的圖片縮放圖了。

  實現代碼如下:

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

  options.inJustDecodeBounds = true;

  // 記得把assets目錄下的圖片拷貝到SD卡中

  // 由於設置inJustDecodeBounds爲true,因此執行下面代碼後bitmap爲空

  mBitmap = BitmapFactory.decodeFile("/sdcard/image.jpg", options);

  // 計算縮放比例,由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可

  int scale = (int) (options.outHeight / (float) 200);

  // 因爲結果爲int型,如果相除後值爲0.n,則最終結果將是0

  if (scale <= 0)

  {

  scale = 1;

  }

  System.out.println("Scale=" + scale);

  options.inSampleSize = scale;

  options.inJustDecodeBounds = false;

  // 重新讀入圖片,注意此時已經把options.inJustDecodeBounds設回false

  mBitmap = BitmapFactory.decodeFile("/sdcard/image.jpg", options);

  int width = mBitmap.getWidth();

  int height = mBitmap.getHeight();

  System.out.println(width + " " + height);

  ImageView image = (ImageView) findViewById(R.id.image);

  image.setImageBitmap(mBitmap);

這樣我們就可以讀取較大的圖片而不會出現內存溢出問題了。

如果你想把壓縮後的圖片保存在sdcard上的話,通過如下代碼就可以了:

File file = new File("/sdcard/ruoshui.png");

  try

  {

  //記得添加sdcard讀寫權限

  FileOutputStream out = new FileOutputStream(file);

  if (mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out))

  {

  out.flush();

  out.close();

  Toast.makeText(MainActivity.this, "保存成功!", Toast.LENGTH_LONG).show();

  }

  }catch (Exception e)

  {

  e.printStackTrace();

  Toast.makeText(MainActivity.this, "保存失敗!", Toast.LENGTH_LONG).show();

  }

方法2:按長寬各自比例進行縮放

上面的方法縮放保存是按長寬比例的,我們當然也可以按固定大小進行縮放:

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

  options.inJustDecodeBounds = false;

  // 記得把assets目錄下的圖片拷貝到SD卡中

  // 由於設置inJustDecodeBounds爲true,因此執行下面代碼後bitmap爲空

  mBitmap = BitmapFactory.decodeFile("/sdcard/image.jpg", options);

  int bmpWidth = mBitmap.getWidth();

  int bmpHeight = mBitmap.getHeight();

  // 縮放圖片的尺寸

  float scaleWidth = (float) sWidth / bmpWidth; // 按固定大小縮放 sWidth 寫多大就多大

  float scaleHeight = (float) sHeight / bmpHeight; //

  Matrix matrix = new Matrix();

  matrix.postScale(scaleWidth, scaleHeight);// 產生縮放後的Bitmap對象

  Bitmap resizeBitmap = Bitmap.createBitmap(mBitmap, 0, 0, bmpWidth, bmpHeight, matrix, false);

  mBitmap.recycle();

  ImageView image = (ImageView) findViewById(R.id.image);

  image.setImageBitmap(resizeBitmap);



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章