用Java快速加载大图像的部分

时间:2013-11-21 18:59:40

标签: java image

我有一个应用程序需要显示一个非常大的图像(来自磁盘上的png),只有一小部分图像可以在屏幕上随时显示。但是,可见部分可以在大图像周围快速移动。

将整个图像一次加载到BufferedImage中并不是一个好主意,因为它可能是10 000 - 100 000像素宽,但磁盘上的大小不是很大(也许是几MB)所以这是一个问题仅加载要显示的相关部分。

我尝试过像这样创建一个ImageReader:

FileImageInputStream is = new FileImageInputStream(imageFile);
ImageReader imageReader = ImageIO.getImageReaders(is).next();
ImageReader.setInput(is, false, true);
ImageReadParam readParameters = imageReader.getDefaultReadParam();

然后获得像这样的子图像的方法:

private BufferedImage loadFrame(int x, int y, int w, int h) {
    readParameters.setSourceRegion(new Rectangle(x,y,w,h));
    try {
        return imageReader.read(0, readParameters);
    } catch (IOException ex) {
        return null;
    }
}

原则上这是有效的,但它太慢了。因此,当快速移动图像时,它会滞后太多。

我还尝试过预先拆分源图像,因此我在磁盘上放了一堆较小的图像,然后根据需要使用ImageIO.read(getImageFile(x,y))加载getImageFile(x,y)将返回相应的File那个位置。这种方法实际上更快,更完全可用。

所以我想我有办法让这项工作成功,但这样做似乎有点尴尬。除了需要对源映像进行一些准备之外,它还需要大量的磁盘访问(尽管我猜这可能是在某处缓冲的。)

所以我的问题是:最好的方法是什么? (为什么从磁盘加载图像比从ImageReader加载图像的一部分更快?)

1 个答案:

答案 0 :(得分:2)

PNG是一种压缩格式,你不能只是打开文件并寻找一个特定的位置来开始读取区域(就像你可以用位图〜当然读取文件头后)。在开始提取区域之前,需要加载(解析/解压缩)整个PNG。 (http://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header

如果你想牺牲磁盘空间来改善内存(RAM)的使用和性能......

  • 您可以将图像分割并仅加载为用户构建视图所需的网格块。
    • 1x1.png,1x2.png,2x1.png,2x2.png - 如果用户正在查看左上角,则只需加载1x1.png等等。
  • 您可以将图像转换为位图BMP图像在磁盘上会大得多,但您无需处理整个文件就可以提取它的特定区域。