我需要逐像素地读取和写入图像(我正在生成Fractals)。当我尝试使用图像大小时,我意识到当图像大小很大(例如24000x18000)时使用BufferedImage
写入图像会导致OutOfMemoryError
。为了解决这个问题,我使用-Xmx -Xms
来增加堆大小。
有没有办法以像素方式写入图像而无需将整个图像加载到内存中?读取(和修改)大图像也是如此。
编辑
我是逐像素,从左到右,从上到下进行的。
答案 0 :(得分:4)
最简单的解决方案通常只是添加更多内存。 : - )
但是,有一些选项(我在你的问题中找不到足够的信息来决定哪一个是最好的,考虑更新它):
为您的图像编写最小格式标题(BMP非常简单,TIFF也可行),以该格式分配图像所需的磁盘空间,以及该区域的内存映射。这与使用虚拟内存类似。系统会一次将文件区域复制到内存中,因此您应该一次在有限的区域内工作以避免过多的交换。
我已经编写了一些类来允许将这样的文件用作(非常慢)BufferedImage
,MappedImageFactory
和MappedFileBuffer
。这些可以与上述相结合,以获得" 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。图像未加载到内存中,但存储在文件中。