2013-12-16 56 views
0

我在我的Android應用程序中構建了一個imagepicker,爲此我使用了example code on this page。這基本上給了我一個按鈕,可以從SD卡上獲取文件,或者通過拍照來打開文件。一旦我選擇了一個圖像,它會使用一個簡單的ImageView來顯示圖像。一般來說,這很好地工作;我可以選擇一個圖像,然後再次單擊選擇圖像按鈕並選擇另一個圖像。到目前爲止這麼好..與小文件是。OutOfMemoryError與Android中的圖像選擇。如何在將圖像解碼爲位圖之前調整圖像大小?

當我使用「較大的文件」時,問題就開始了;我只是用內置的手機相機拍下的照片。我可以選擇一個,而且效果很好。當我再次打了選擇圖像按鈕,然後選擇另一個形象,我就在這行一個OutOfMemoryError(線鏈接到頁面75):

bitmap = BitmapFactory.decodeFile(path); 

我的測試設備是一個相當現代化的一個(銀河S4迷你),所以不應該是這個問題。因爲我需要將圖像發送爲Base64字符串,對此我總有需要調整它的API,我可以用這樣的調整圖像大小:

Bitmap yourBitmap; 
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true); 

但不幸的是,爲了這個,我首先需要解碼該文件實際上首先導致問題。

所以我的問題是,有沒有一種方法可以在將圖像解碼爲位圖之前調整圖像大小?歡迎所有提示!

+0

更改位圖的大小: http://stackoverflow.com/questions/4837715/how-to-resize-a-bitmap-in-android 希望這將有助於。 – Yogendra

回答

5

雖然加載大的位圖文件,BitmapFactory類提供了幾種解碼方法(decodeByteArray(),decodeFile(),decodeResource(),等等)。

STEP 1

的inJustDecodeBounds屬性設置爲true,而解碼避免了內存分配,爲位圖對象返回空但設置outWidth,outHeight和outMimeType。該技術允許您在構建位圖之前讀取圖像數據的尺寸和類型(以及內存分配)。

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 
BitmapFactory.decodeResource(getResources(), R.id.myimage, options); 
int imageHeight = options.outHeight; 
int imageWidth = options.outWidth; 
String imageType = options.outMimeType; 

要避免java.lang.OutOfMemory異常,請在解碼之前檢查位圖的維數。

STEP 2

告訴解碼器子樣本圖像,加載一個較小的版本到內存中,設置inSampleSize爲true你BitmapFactory.Options對象。

例如,分辨率爲2048x1536且用inSampleSize爲4解碼的圖像會生成大約512x384的位圖。將其加載到內存中時,整個圖像使用0.75MB而不是12MB。

這裏的計算樣本大小值是兩個基於目標寬度和高度的功率的方法:

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); 
} 

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; 
} 

請仔細閱讀本鏈接瞭解詳情。 http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

1

避免這種錯誤,清單中使用該AQUIRE一大堆:

android:largeHeap="true" 

然後根據你的需要

+0

這真的幫我解決了我的問題。 –

1

試試這個我曾經用它解碼位圖,再大小。它爲我工作。

private Bitmap getBitmap(String path) { 

    Uri uri = getImageUri(path); 
    InputStream in = null; 
    try { 
     final int IMAGE_MAX_SIZE = 1200000; // 1.2MP 
     in = mContentResolver.openInputStream(uri); 

     // Decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     BitmapFactory.decodeStream(in, null, o); 
     in.close(); 



     int scale = 1; 
     while ((o.outWidth * o.outHeight) * (1/Math.pow(scale, 2)) > 
       IMAGE_MAX_SIZE) { 
      scale++; 
     } 
     Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ", 
      orig-height: " + o.outHeight); 

     Bitmap b = null; 
     in = mContentResolver.openInputStream(uri); 
     if (scale > 1) { 
      scale--; 
      // scale to max possible inSampleSize that still yields an image 
      // larger than target 
      o = new BitmapFactory.Options(); 
      o.inSampleSize = scale; 
      b = BitmapFactory.decodeStream(in, null, o); 

      // resize to desired dimensions 
      int height = b.getHeight(); 
      int width = b.getWidth(); 
      Log.d(TAG, "1th scale operation dimenions - width: " + width + ", 
       height: " + height); 

      double y = Math.sqrt(IMAGE_MAX_SIZE 
        /(((double) width)/height)); 
      double x = (y/height) * width; 

      Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, 
       (int) y, true); 
      b.recycle(); 
      b = scaledBitmap; 

      System.gc(); 
     } else { 
      b = BitmapFactory.decodeStream(in); 
     } 
     in.close(); 

     Log.d(TAG, "bitmap size - width: " +b.getWidth() + ", height: " + 
      b.getHeight()); 
     return b; 
    } catch (IOException e) { 
     Log.e(TAG, e.getMessage(),e); 
     return null; 
    } 
2

基本上,您應該使用BitmapFactory.decodeFile(path, options)傳遞Bitmap.Options.inSampleSize來解碼原始位圖的子採樣版本。

您的代碼將是這個樣子:

public Bitmap decodeBitmap(String path, int maxWidth, int maxHeight) { 
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(path, options); 
    options.inJustDecodeBounds = false; 
    options.inSampleSize = calculateInSampleSize(maxWidth, maxHeight, options.outWidth, options.outHeight); 
    return BitmapFactory.decodeFile(path, options); 
} 

而且calculateInSampleSize代碼:

private int calculateInSampleSize(int maxWidth, int maxHeight, int width, int height) { 
    double widthRatio = (double) width/maxWidth; 
    double heightRatio = (double) height/maxHeight; 
    double ratio = Math.min(widthRatio, heightRatio); 
    float n = 1.0f; 
     while ((n * 2) <= ratio) { 
      n *= 2; 
     } 
     return (int) n; 
    } 
1

您可以使用圖像採集其加載較小尺寸的圖像,而無需加載大。你可以用Options參數傳遞給BitmapFactory。設置Options.inJustDecodeBoundstrue並且BitmapFactory會將Options.outWidth和Options.outHeight字段設置爲圖像的原始大小。請注意,將inJustDecodeBounds設置爲true時,返回的位圖爲空。還可以使用Options.inSampleSize解碼採樣圖像。樣本大小顯示結果圖像縮小的程度。

相關問題