Android - 旋转图像,避免OutOfMemory

时间:2013-08-22 04:20:07

标签: android image-processing bitmap heap

下面的代码可以导致OutOfMemory吗?我认为它允许超出应用程序内存限制。

Matrix matrix = new Matrix();
matrix.postRotate(orientation);

image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);

在Android中旋转图片的最佳方法是什么?

在新进程的服务中分配它以获得更多堆?

@CommonsWare在这个链接[1]中说,许多开发人员认为更多的堆是低效编码的解决方案。

这个问题也表明大堆[2]。

是否有更简单的解决方案?

[1] Can you start an IntentService on a separate process?

[2] How to avoid OutOfMemory ex while rotating the image?

4 个答案:

答案 0 :(得分:2)

简短的回答是,是的,此代码可能会导致OutOfMemory。我认为没有比增加app堆大小更简单的解决方案。我相信@CommonsWare是正确的,并且OutOfMemory经常表示编程错误。但是在某些情况下,你需要,嗯,巨大的记忆。旋转巨大的图像绝对是这种情况之一。

您可以使用本机代码(NDK)而不是要求增加堆大小,但这绝对不容易。它仍然需要大量内存,因此使用C ++没有任何优势(除了它适用于2.3)。

答案 1 :(得分:1)

如果您希望使用基于NDK的解决方案,我创建了一个here,并且我已经创建了一个github项目here

这样可以通过将数据放入本机C“world”来避免OOM,回收旧数据,并在轮换后返回结果。

它不需要任何下采样。<​​/ p>

答案 2 :(得分:0)

当您的位图要大到要加载到内存中时抛出OutOfMemoryException。

我在这里给你一个解决方案。

BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is,null,options);

使用BitmapFactory.Options类的inSampleSize属性。

如果设置为值&gt;如图1所示,请求解码器对原始图像进行二次采样,返回较小的图像以节省存储器。样本大小是任一维度中对应于解码位图中的单个像素的像素数。例如,inSampleSize == 4返回的图像是原始宽度/高度的1/4,像素数量的1/16。任何值&lt; = 1都被视为1.注意:解码器使用基于2的幂的最终值,任何其他值将向下舍入到最接近的2的幂。

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
    //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(new FileInputStream(f),null,o);

    //The new size we want to scale to
    final int REQUIRED_SIZE=70;

    //Find the correct scale value. It should be the power of 2.
    int scale=1;
    while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
        scale*=2;

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize=scale;
    return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}

答案 3 :(得分:0)

下面:

image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);

代码运行两个位图,第一个image是一个Bitmap,你先前加载/解码到RAM中工作 - 实际旋转。第二个将由Bitmap.createBitmap()创建,无论您将结果存储到同一个变量中。无论如何,在这一行,你需要位图x2 RAM,这肯定会导致OOM(说到设备的最大可能照片)。
我认为使用NDK是最好的解决方案。
请检查my very same question here以获取其他可能的解决方案(MappedByteBuffer),它还包含指向NDK / JNI解决方案的链接。