读写大图像

时间:2016-05-30 05:09:47

标签: java image out-of-memory bufferedimage

我需要逐像素地读取和写入图像(我正在生成Fractals)。当我尝试使用图像大小时,我意识到当图像大小很大(例如24000x18000)时使用BufferedImage写入图像会导致OutOfMemoryError。为了解决这个问题,我使用-Xmx -Xms来增加堆大小。

有没有办法以像素方式写入图像而无需将整个图像加载到内存中?读取(和修改)大图像也是如此。

编辑

我是逐像素,从左到右,从上到下进行的。

2 个答案:

答案 0 :(得分:4)

最简单的解决方案通常只是添加更多内存。 : - )

但是,有一些选项(我在你的问题中找不到足够的信息来决定哪一个是最好的,考虑更新它):

  • 为您的图像编写最小格式标题(BMP非常简单,TIFF也可行),以该格式分配图像所需的磁盘空间,以及该区域的内存映射。这与使用虚拟内存类似。系统会一次将文件区域复制到内存中,因此您应该一次在有限的区域内工作以避免过多的交换。

  • 我已经编写了一些类来允许将这样的文件用作(非常慢)BufferedImageMappedImageFactoryMappedFileBuffer。这些可以与上述相结合,以获得" live"更新文件,或使用更熟悉的ImageIO API来读取/写入大文件(读取此类图像所需的特殊代码,请参阅MappedImageFactory.createCompatibleMappedImage(w, h, type)ImageReadParam.setDestination(image))。

  • 使用ImageIO API读取和写入切片(固定大小的区域)。我所知道的唯一支持图块的图像格式是TIFF。我认为来自TIFFImageReader的{​​{1}}和TIFFImageWriter将支持平铺。 ja_imageio.jar API支持平铺。 Tiling也可能与内存映射技术结合使用,以获得更好的性能(即将tile复制到正常RenderedImage以便更快地进行Java2D操作)。

  • 使用BufferedImage API读取和写入任意子区域。使用ImageIO轻松阅读某个地区。 ImageReadParam.setSourceRegion(...)方法将告诉您作者是否支持编写区域。不幸的是,我不知道目前支持这种情况的任何ImageWriter.canReplacePixels()实现,但理论上,如果您想自己实现它,那么对于任何未压缩的格式应该很容易。

此列表可能并非详尽无遗。

答案 1 :(得分:1)

我同意haraldK提出的解决方案。 18Kx24K可轻松加载到内存中。

但是,当您逐个像素地移动时,您还可以使用BigBufferedImage中显示的this post。图像未加载到内存中,但存储在文件中。