读取和写入大图像
Read and Write a large Image
我需要逐像素读取和写入图像(我正在生成分形)。当我尝试图像尺寸时,我意识到当图像尺寸很大(比如 24000x18000)时,使用 BufferedImage
写入图像会导致 OutOfMemoryError
。为了解决这个问题,我使用 -Xmx -Xms
来增加堆大小。
有没有办法以像素方式写入图像,而不必将整个图像加载到内存中?读取(和修改)大图像也是如此。
编辑
我是一个像素一个像素地做的,从左到右,从上到下。
最简单的解决方案通常就是增加内存。 :-)
但是,有一些选项(我在你的问题中找不到足够的信息来决定哪个是最好的,考虑更新它):
为您的图像写一个最小格式header(BMP很容易,TIFF也可以),分配您的图像所需的磁盘space格式,和内存映射该区域。这类似于使用虚拟内存。系统会一次将文件的区域复制到内存中,因此您应该一次只在有限的区域上工作,以避免交换过多。
我写了一些 类 允许使用这样的文件作为(相当慢)BufferedImage
、MappedImageFactory
and MappedFileBuffer
。这些可以与上面的组合,有一个 "live" 更新文件,或者使用更熟悉的 ImageIO
API 到 read/write 大文件(需要特殊代码读入此类图像,请参阅 MappedImageFactory.createCompatibleMappedImage(w, h, type)
和 ImageReadParam.setDestination(image)
)。
使用ImageIO
API读写tile(固定大小的区域)。据我所知,唯一支持平铺的图像格式是 TIFF。我认为来自 ja_imageio.jar
的 TIFFImageReader
和 TIFFImageWriter
将支持平铺。 RenderedImage
API 中也支持平铺。平铺也可能与内存映射技术相结合,以获得更好的性能(即将平铺复制到正常 BufferedImage
以实现更快的 Java2D 操作)。
使用ImageIO
API读写任意子区域。使用 ImageReadParam.setSourceRegion(...)
读取区域很容易。 ImageWriter.canReplacePixels()
方法会告诉您编写器是否支持写入区域。不幸的是,我不知道目前有任何 ImageWriter
实现支持此功能,但从理论上讲,如果您想自己实现它,对于任何未压缩格式来说都应该很容易。
此列表可能并不详尽。
我同意haraldK提出的解决方案。 18Kx24K可以轻松加载到内存中。
但是随着逐个像素地移动,您也可以使用 BigBufferedImage that was presented into this post。图像没有加载到内存中,而是存储到文件中。
我需要逐像素读取和写入图像(我正在生成分形)。当我尝试图像尺寸时,我意识到当图像尺寸很大(比如 24000x18000)时,使用 BufferedImage
写入图像会导致 OutOfMemoryError
。为了解决这个问题,我使用 -Xmx -Xms
来增加堆大小。
有没有办法以像素方式写入图像,而不必将整个图像加载到内存中?读取(和修改)大图像也是如此。
编辑
我是一个像素一个像素地做的,从左到右,从上到下。
最简单的解决方案通常就是增加内存。 :-)
但是,有一些选项(我在你的问题中找不到足够的信息来决定哪个是最好的,考虑更新它):
为您的图像写一个最小格式header(BMP很容易,TIFF也可以),分配您的图像所需的磁盘space格式,和内存映射该区域。这类似于使用虚拟内存。系统会一次将文件的区域复制到内存中,因此您应该一次只在有限的区域上工作,以避免交换过多。
我写了一些 类 允许使用这样的文件作为(相当慢)
BufferedImage
、MappedImageFactory
andMappedFileBuffer
。这些可以与上面的组合,有一个 "live" 更新文件,或者使用更熟悉的ImageIO
API 到 read/write 大文件(需要特殊代码读入此类图像,请参阅MappedImageFactory.createCompatibleMappedImage(w, h, type)
和ImageReadParam.setDestination(image)
)。使用
ImageIO
API读写tile(固定大小的区域)。据我所知,唯一支持平铺的图像格式是 TIFF。我认为来自ja_imageio.jar
的TIFFImageReader
和TIFFImageWriter
将支持平铺。RenderedImage
API 中也支持平铺。平铺也可能与内存映射技术相结合,以获得更好的性能(即将平铺复制到正常BufferedImage
以实现更快的 Java2D 操作)。使用
ImageIO
API读写任意子区域。使用ImageReadParam.setSourceRegion(...)
读取区域很容易。ImageWriter.canReplacePixels()
方法会告诉您编写器是否支持写入区域。不幸的是,我不知道目前有任何ImageWriter
实现支持此功能,但从理论上讲,如果您想自己实现它,对于任何未压缩格式来说都应该很容易。
此列表可能并不详尽。
我同意haraldK提出的解决方案。 18Kx24K可以轻松加载到内存中。
但是随着逐个像素地移动,您也可以使用 BigBufferedImage that was presented into this post。图像没有加载到内存中,而是存储到文件中。