2013-12-16 33 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解码采样图像。样本大小显示结果图像缩小的程度。

相关问题