读取和写入大图像

Read and Write a large Image

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

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

编辑

我是一个像素一个像素地做的,从左到右,从上到下。

最简单的解决方案通常就是增加内存。 :-)

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

  • 为您的图像写一个最小格式header(BMP很容易,TIFF也可以),分配您的图像所需的磁盘space格式,和内存映射该区域。这类似于使用虚拟内存。系统会一次将文件的区域复制到内存中,因此您应该一次只在有限的区域上工作,以避免交换过多。

  • 我写了一些 类 允许使用这样的文件作为(相当慢)BufferedImageMappedImageFactory and MappedFileBuffer。这些可以与上面的组合,有一个 "live" 更新文件,或者使用更熟悉的 ImageIO API 到 read/write 大文件(需要特殊代码读入此类图像,请参阅 MappedImageFactory.createCompatibleMappedImage(w, h, type)ImageReadParam.setDestination(image))。

  • 使用ImageIOAPI读写tile(固定大小的区域)。据我所知,唯一支持平铺的图像格式是 TIFF。我认为来自 ja_imageio.jarTIFFImageReaderTIFFImageWriter 将支持平铺。 RenderedImage API 中也支持平铺。平铺也可能与内存映射技术相结合,以获得更好的性能(即将平铺复制到正常 BufferedImage 以实现更快的 Java2D 操作)。

  • 使用ImageIOAPI读写任意子区域。使用 ImageReadParam.setSourceRegion(...) 读取区域很容易。 ImageWriter.canReplacePixels() 方法会告诉您编写器是否支持写入区域。不幸的是,我不知道目前有任何 ImageWriter 实现支持此功能,但从理论上讲,如果您想自己实现它,对于任何未压缩格式来说都应该很容易。

此列表可能并不详尽。

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

但是随着逐个像素地移动,您也可以使用 BigBufferedImage that was presented into this post。图像没有加载到内存中,而是存储到文件中。