0

我目前正在制作一个修改图像某些字节的 Android 应用程序。为此,我编写了以下代码:

Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(path));
ByteBuffer buffer = ByteBuffer.allocate(bmp.getWidth()*bmp.getHeight());
bmp.copyPixelsToBuffer(buffer);
return buffer.array();

问题是这种方式使用了太多的堆内存,并且抛出了OutOfMemoryException. 我知道我可以让 App 的堆内存更大,但这似乎不是一个好的设计选择。

有没有更方便内存的方式来改变图像的字节数?

4

1 回答 1

1

看起来托管堆上有两个像素数据副本:

  • 未压缩的数据在Bitmap
  • 中的数据副本ByteBuffer

getPixel()通过将数据留在位图中并使用/ setPixel()(或者可能使用“批量”变体一次编辑一行),内存需求可以减半,但这会增加一些开销。

根据图像的性质,您可以使用不太精确的格式(例如 RGB 565 而不是 8888),从而将内存需求减半。

如其中一条评论所述,您可以将数据解压缩到文件中,java.nio.channels.FileChannel#map()使用 对其进行内存映射,然后通过MappedByteBuffer. 这为加载和保存增加了相当多的开销,并且可能很烦人,因为您必须通过 aByteBuffer而不是 a byte[]

android:largeHeap另一种选择是使用(在此处记录)扩展堆,尽管在某些方面您只是推迟了不可避免的事情:您可能会被要求编辑对于“大”堆来说太大的图像。此外,“大”堆的容量因设备而异,就像“正常大小”的堆一样。这是否有意义部分取决于您正在加载的图像有多大。

在您执行任何此操作之前,我建议您使用堆分析工具(参见例如此博客文章)来查看您的内存去向。另外,看一下内存不足异常上面的logcat;它应该识别失败的分配的大小。确保它看起来“合理”,即你不会无意中分配比你想象的更多的东西。

于 2013-06-20T20:39:25.660 回答