如何在Java中加载大图像

时间:2009-07-13 13:45:19

标签: java image

我正在尝试在Java中加载大图像文件,如果文件太大(我已经尝试通过命令行标志增加堆大小),我会收到内存错误消息。

我正在使用以下方式加载图片:

如果图像不是tiff图像,我正在使用此代码:

BufferedImage img = ImageIO.read(fileToOpen);

如果文件是tiff,我正在使用此代码:

BufferedImage img = JAI.create("fileload", 
    fileToOpen.getAbsolutePath()).getAsBufferedImage();

我的问题实际上归结为:图像处理程序(例如Photoshop)如何加载数百兆字节的文件而不会出现内存错误?

据我所知,20MB jpeg难以加载到内存中的原因是因为在加载到BufferedImage时,例如以非压缩方式保存图像。因此,一种可能的解决方案是拥有一个Java类,该类是Image抽象类的子类,但以压缩形式存储数据。但这可能会有速度问题,因为运行时机器必须在绘制时解压缩数据。另一个选择是将原始未压缩数据缓存到磁盘并从那里无缝读取,但速度问题仍然存在。

大男孩怎么做呢? Photoshop如何在内存中加载200MB jpeg并绘制所有分辨率而没有任何明显问题?

(最后注意:在我的应用程序中,由于速度问题,我得到我的BufferedImage后,我将其内容绘制到具有相同尺寸的VolatileImage上。这大大提高了绘图速度)

3 个答案:

答案 0 :(得分:5)

未压缩的RGBA图像所需的内存是宽*高* 4字节。尝试根据此设置你的记忆。底层JDK / DirectX /等可能存在大小上限限制。系统虽然。

大男孩利用JPG图像的结构,他们不需要将其加载到内存中。也许他们每次都直接从文件中提取它。

BufferedImage具有类似于易失性图像的自动加速功能。将加速度优先级设置为1,第一个绘制将在最新的JDK上将其移动到VRAM。

编辑我认为您正在运行32位系统。如果您的未压缩图像非常大,超过1.4GB,则由于JVM限制,您将无法在内存中处理它。如果图像不是一次性图像,那么您可以找到将其解压缩为临时原始图像的工具,并使用随机文件访问来抓取部分图像。

答案 1 :(得分:3)

技巧不是处理全尺寸图像。将其划分为可管理的部分,如当前分辨率的50 x 50像素,并在需要时从原始文件生成内容。如果不需要给定的片段(例如,屏幕外),则可以将其删除(弱引用将是完美的)或持久保存到磁盘。

答案 2 :(得分:0)

解决方案是BigBufferedImage。它可以加载和存储比内存限制更大的图像。诀窍是它的缓冲区被基于文件的DataBuffer实现所取代。它将图像存储在硬盘驱动器上。没有使用RAM。这可以防止OutOfMemoryException。

从图片文件创建BigBufferedImage:

BigBufferedImage image = BigBufferedImage.create(
        inputFile, tempDir, TYPE_INT_RGB);

创建一个空的BigBufferedImage:

BigBufferedImage image = BigBufferedImage.create(
        tempDir, width, height, TYPE_INT_RGB);

有关大图像处理的更多信息read this article