加入大图像时出现OutOfMemory错误

时间:2011-06-02 11:03:04

标签: android bitmap out-of-memory

我正在使用下面的代码加入两张图片,但它会导致OutOfMemory错误,我的图片大约每张1MB。

private Bitmap overlayMark(String first, String second)
{
    Bitmap bmp1, bmp2;
    bmp1 = BitmapFactory.decodeFile(first);
    bmp2 = BitmapFactory.decodeFile(second);
    if (bmp1 == null || bmp2 == null)
        return bmp1;

    int height = bmp1.getHeight();
    if (height < bmp2.getHeight())
        height = bmp2.getHeight();

    Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth() + bmp2.getWidth(), height,
            Bitmap.Config.ARGB_8888);// Out of memory
    Canvas canvas = new Canvas(bmOverlay);
    canvas.drawBitmap(bmp1, 0, 0, null);
    canvas.drawBitmap(bmp2, bmp1.getWidth(), 0, null);
    bmp1.recycle();
    bmp2.recycle();
    return bmOverlay;
}

更新:我尝试了以下两个答案,但仍然没有完全创建如此大尺寸的位图,问题是结果位图的大小太大,大约2400x3200,所以内存不足

如何在不耗尽内存的情况下加入大型图片?

7 个答案:

答案 0 :(得分:13)

如果不将图像加载到内存中,您可以使用inJustDecodeBounds获取图像的大小。 Bitmap返回null,但所有参数都已设置。您可以相应缩小图像。

如果您的JPEG图像各为1 MiB,转换为BMP确实会占用大量内存。您可以通过图像的尺寸轻松计算其BMP等效值。预计这种大图像的转换确实会崩溃。 Android仅将其应用限制为16 MiB VM。

也可以使用RGB_565代替ARGB_8888。

所以你唯一的解决方案是: (a)使用BitmapFactory.Options.inSampleSize缩小图像 要么 (b)使用Android NDK,其中不存在16 MiB限制。

答案 1 :(得分:5)

我使用这个简单的拇指规则: 繁重的提升(内存/ CPU)都在服务器上完成。

所以编写一些获取图像的servlet,将其调整到指定的维度(可能也会减小像素深度)并返回结果。

小蛋糕,它适用于您需要的任何移动设备。

祝你好运!

答案 2 :(得分:4)

我认为像Sumon这样的解决方案可能有用。

  • 弄清楚决赛的大小 图像基于什么适合 屏幕。
  • 使用获取第一张图片的大小 inJustDecodeBounds技术。 弄清楚第一个的大小 最终图像中的图像。计算 重新调整参数大小。
  • 调整图像大小,加载到内存中。
  • 将已调整大小的图像写回磁盘。 回收位图。 (这会有所帮助 调整第二张图片的大小时)
  • 重复第二张图片,只有你 可以跳过写入磁盘部分。
  • 加载第一张图片。

如果您只需要显示,那就这样做吧。如果没有,那么此时您可以合并为一个位图并写入磁盘。如果是这种情况,可能会很困难,因为你的内存屏幕大小基本上是2倍。在这种情况下,我建议调整较小的尺寸。如果你不能变小,那么你必须走NDK路线,以为我不确定how much that will help。这是NDK和JNI的amusing intro。最后,我强烈建议使用运行Android 2.3+的手机进行开发,因为使用堆分配的位图将使调试更容易。有关here的更多信息。

答案 3 :(得分:3)

位图的内存中表示占用的空间不必与文件大小紧密对应。所以即使你有3mb内存可用于jvm,你仍然可能会得到OutOfMemoryException。

您的代码同时创建了三个内存中的图像。如果您可以在不读取完整文件的情况下找到两个图像的大小,则可以修改代码,以便一次只在内存中包含一个源图像。如果即使这还不够,您可能需要某种流式读取图像的方法。

答案 4 :(得分:3)

你可以从here得到一些想法。

答案 5 :(得分:3)

您是要尝试显示此超大图像,还是只是想保存它?

  1. 如果您尝试显示它。将图像切割成瓷砖。然后只显示正在查看的图块。如果用户缩小,则需要在显示整个内容之前减小位图的大小。

  2. 如果您尝试保存,请尝试通过剪切图像将其保存到同一文件中。

  3. 在内存中加载2个1m文件,然后创建一个2m文件,仅为您的图像留出4M内存。动态加载和卸载内存可解决此问题,类似于Google地图上的图块或其他面向地图的解决方案中的动态缩放。

答案 6 :(得分:3)

如果您需要返回那个巨大的2400x3200位图作为结果,则无法实际实现此目标。原因是2400 * 3200 * 4字节~30 Mb!你怎么能希望实现这个方法,即使你甚至不能将返回值放入有限的堆空间(即16Mb)?

即使您使用了16位颜色,它仍然会失败,因为您最终会使用大约15MB,这不会为语言运行时留下足够的空间。