Android:对图像字节进行内存友好修改

时间:2013-06-20 15:24:50

标签: java android bitmap bitmapfactory

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

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

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

是否有更加内存友好的方式来更改图像的字节?

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

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

在你做任何这些之前,我建议你使用堆分析工具(参见例如this blog post)来查看你的记忆力。另外,查看内存不足异常之上的logcat;它应该确定失败的分配大小。确保它看起来“合理”,即你不会无意中分配比你想象的更多的东西。