2013-11-21 44 views
4

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

将整个图像一次加载到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加载图像的一部分更快?)

回答

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,但磁盘上的图像会更大,但您可以在不必处理整个文件的情况下提取特定区域。
+0

好的。我想我认为只能解压缩PNG的一部分是可能的,但考虑到它,我想设计一种压缩格式并不容易或有效,因为这种压缩格式可以这样工作(显然,PNG不是这样的格式)。感谢您的回答! – zephyr