简体   繁体   English

如何通过BufferedImage将巨大的图像加载到Java?

[英]How do I load an enormous image to Java via BufferedImage?

I want to load large images (18000 x 18000) to my application. 我想将大图像(18000 x 18000)加载到我的应用程序中。 If i use BufferedImage with type int_rgb , I need around 1235mb of heap memory to load. 如果我使用类型为int_rgb BufferedImage ,我需要大约1235mb的堆内存来加载。 This is a very high amount of memory, and end users will likely have less ram (1GB or less). 这是一个非常大的内存量,最终用户可能会有更少的内存(1GB或更少)。

On my development PC, when I load the image from MyEclipse IDE, it throws an out of memory Exception . 在我的开发PC上,当我从MyEclipse IDE加载图像时,它会抛出一个内存不足的Exception When i pack my code to an executable jar and run it on my PC external of Eclipse, it still throws an exception. 当我将我的代码打包到一个可执行jar并在Eclipse外部的PC上运行时,它仍然会抛出异常。

How do I load such a large image into my application using buffered image without using 1235mb of memory? 如何在不使用1235mb内存的情况下使用缓冲图像将如此大的图像加载到我的应用程序中? Is there a trick, like splitting the image into smaller portions like image segmentation? 有没有一个技巧,比如将图像分成像图像分割这样的较小部分?

I found this thread on SO , but it not useful for me; 在SO上找到了这个帖子 ,但它对我没用; I want to load the image into BufferedImage and then draw it on a Panel using the Graphics class. 我想将图像加载到BufferedImage ,然后使用Graphics类在Panel上绘制它。

You can read and display fragments of the image using ImageReadParam from ImageIO package. 您可以使用ImageIO包中的ImageReadParam读取和显示图像的片段。 Here is a basic example that illustrates how to read a single fragment using ImageReadParam without reading the whole image: 这是一个基本示例,说明如何使用ImageReadParam读取单个片段而不读取整个图像:

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();
            }
        });
    }
}

The result looks like this: 结果如下:

在此输入图像描述

Generally, you'd need to do something like this: 通常,您需要执行以下操作:

  • Break the image into manageable size image files and store them on disk with your application. 将图像分解为可管理的大小图像文件,并将其与应用程序一起存储在磁盘上。
  • When displaying a particular part of this image, only the load and display image fragments that overlap your viewport. 显示此图像的特定部分时,仅显示与视口重叠的加载和显示图像片段。
  • As you pan around the image, update the loaded and displayed image fragments appropriately. 在平移图像时,适当更新已加载和显示的图像片段。
  • Either let the unnecessary image fragments get collected by the GC or load new ones in such a way that they overwrite older ones. 要么让GC收集不必要的图像片段,要么加载新的图像片段以覆盖旧的片段。 (This last argues for identically-sized image fragments that load into pooled memory buffers.) (最后争论的是相同大小的图像片段加载到池化的内存缓冲区中。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM