7

我想将大图像 (18000 x 18000) 加载到我的应用程序中。如果我使用BufferedImagetype int_rgb,我需要大约 1235mb 的堆内存来加载。这是一个非常大的内存量,最终用户的内存可能会更少(1GB 或更少)。

在我的开发 PC 上,当我从 MyEclipse IDE 加载图像时,它会抛出内存不足Exception。当我将代码打包到可执行 jar 并在 Eclipse 外部的 PC 上运行时,它仍然会引发异常。

如何在不使用 1235mb 内存的情况下使用缓冲图像将如此大的图像加载到我的应用程序中?有没有技巧,比如将图像分割成更小的部分,比如图像分割?

在 SO 上找到了这个帖子,但它对我没有用;我想将图像加载到BufferedImage其中,然后Panel使用Graphics该类将其绘制在 a 上。

4

2 回答 2

6

您可以使用包中的ImageReadParam读取和显示图像的片段ImageIOImageReadParam这是一个基本示例,说明了如何在不读取整个图像的情况下读取单个片段:

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.*;

public class TestImageChunks {
    private static void createAndShowUI() {
        try {
            URL url = new URL(
                    "http://duke.kenai.com/wave/.Midsize/Wave.png.png");
            Image chunk = readFragment(url.openStream(), new Rectangle(150,
                    150, 300, 250));
            JOptionPane.showMessageDialog(null, new ImageIcon(chunk), "Duke", 
                    JOptionPane.INFORMATION_MESSAGE);
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, e.getMessage(), "Failure",
                    JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
        }
    }

    public static BufferedImage readFragment(InputStream stream, Rectangle rect)
            throws IOException {
        ImageInputStream imageStream = ImageIO.createImageInputStream(stream);
        ImageReader reader = ImageIO.getImageReaders(imageStream).next();
        ImageReadParam param = reader.getDefaultReadParam();

        param.setSourceRegion(rect);
        reader.setInput(imageStream, true, true);
        BufferedImage image = reader.read(0, param);

        reader.dispose();
        imageStream.close();

        return image;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}

结果如下所示:

在此处输入图像描述

于 2013-03-01T02:20:34.433 回答
2

通常,您需要执行以下操作:

  • 将图像分解为可管理大小的图像文件,并将它们与您的应用程序一起存储在磁盘上。
  • 显示此图像的特定部分时,仅加载和显示与视口重叠的图像片段。
  • 当您平移图像时,适当地更新加载和显示的图像片段。
  • 要么让 GC 收集不必要的图像片段,要么以覆盖旧图像的方式加载新的图像片段。(这最后主张加载到池化内存缓冲区中的相同大小的图像片段。)
于 2013-02-28T18:26:26.860 回答