5

我有一个非常大的高分辨率地图,我想在应用程序中使用它(图像大小约为 80 mb)。

我想知道以下内容:

  • 如何以最佳方式加载此图像?我知道加载图像需要几秒钟(这没关系),但我想通知用户进度。我想使用确定的模式并以某种方式JProgressBar向用户展示。这应该反映已加载的字节数或类似的东西。是否有任何图像加载方法可以提供此功能(如ImageIO.read())?
  • 因为地图的分辨率非常高,我想为用户提供滚动以放大和缩小。我怎样才能以最好的方式做到这一点?我知道BufferedImage这样一个大文件重新调整标准方式需要很长时间。有没有有效的方法来做到这一点?

谢谢您的意见!

亲切的问候,
Héctor van den Boorn

ps 图像将绘制在 JPanel 的画布上。


嗨,安德鲁,非常感谢您的帮助;一切都很完美,加载速度很快。如果没有您的专业知识和解释,我仍然会为此工作,因此您已经公平地赢得了赏金。

我所做的是以下内容;使用 imagemagick 我创建了多个不同分辨率的图像,并且在执行开始时我只加载了最小的 res。图片。其余的加载在单独的线程中,因此不会停止执行。使用您提供给我的信息,然后我在放大或缩小时使用适当的图像。我对使用瓷砖有点怀疑,因为我需要在地图上绘制自己的图像,而我在你告诉我要使用的外部 jar 中找不到绘制功能,所以我最终使用了一些简单的东西;缩放或平移时,重新缩放模式设置为快速,当您不缩放或平移时,重新缩放设置为平滑像素完美图像(就像您建议的那样),但事实证明这足够快,我不'

所以再次感谢,一切都很好:)

4

1 回答 1

3

您应该(同时)采取两种方法:

  1. 将图像缩小为各种尺寸。您应该以一系列较低的分辨率(1/2、1/4、1/8 等,直到图像大约是最大可能的屏幕分辨率)缩小图像。当用户第一次打开图像时,您会显示较低分辨率的图像。这将快速加载并允许用户平移。当用户放大时,您使用更高分辨率的图像。您可以为此使用 ImageMagick:http ://www.imagemagick.org/Usage/resize/
  2. 平铺较大的图像。这将单个大图像分解为网格模式中的大量小图像。当用户放大某个区域时,您可以计算用户正在查看哪些图块,然后只渲染它们,而不渲染图像的其他区域。您可以使用 ImageMagick 将图像拆分为图块,例如ImageMagick。将图像切成小块的正确方法是什么。文档是http://www.imagemagick.org/Usage/crop/#crop_tile

(提供适当大小和平铺图像的缓存使 GoogleEarth 和无数其他地图应用程序能够如此快速地渲染,同时以令人难以置信的高分辨率放大地图)

一旦你有了你的瓦片,你就可以使用 Java 中的几个引擎之一:

可能还有其他人。

您可以在此框架内实现任意缩放(适用于双指缩放或类似缩放)。在您允许的缩放范围内,您的算法将类似于:

  1. 对于用户选择的缩放级别,选择最接近高分辨率缓存。例如,如果您有 100%、50%、25% 和 12.5% 的图块,并且用户选择 33% 缩放,则选择 50% 的图块
  2. 设置拼贴的布局,使拼贴方块具有适合所选缩放的正确大小(这可能是最低缩放级别的单个拼贴)。例如,在使用 50% 平铺的 33% 缩放时,平铺为 100 像素正方形,网格将为 67 像素正方形
  3. 单独加载和缩放平铺图像以适合屏幕(这可以是多线程的,适用于现代 CPU 架构)

有几点需要注意:

  1. 当您达到您拥有瓷砖的最大分辨率时 ,缩放算法会发生变化。
    1. 高达 100% 的图像缩放,使用双线性或双三次缩放。这为几乎没有锯齿的照片提供了出色的外观
    2. 高于 100%,您可能想要显示像素,因此最近邻可能是一个不错的选择
  2. 要获得更高的保真度,请使用更高比例的图块并缩小 > 50%。例如,假设您准备了 100%、50%、25% 和 12.5% 的瓷砖。要显示 40% 的缩放,请不要缩小 50% 的图块;而是使用 100% 的图块并将它们缩小到 40%。这很有用:
    1. 如果您的图像是文本或图表(即包含许多直线的光栅图像)。如果您不过度采样,缩放这些类型的图像通常会产生令人讨厌的伪影
    2. 如果您需要非常高保真度的摄影风格图像
  3. 如果您需要渲染缩放预览(例如,当用户仍在捏和缩放时),请在手势开始时截取屏幕截图并进行缩放。动画流畅比缩放预览像素完美更重要。
  4. 选择合适尺寸的瓷砖很重要。非常大的图块(每个屏幕<1 个)渲染速度很慢。太小的图块会产生其他开销,并且经常会产生令人讨厌的渲染伪影,您会看到屏幕随机填满。性能和复杂性之间的一个很好的折衷方案是使磁贴约为全屏尺寸的四分之一。

使用这些技术时,图像应该加载得更快,因此进度条并不那么重要。如果是,那么您需要在ImageReader上注册一个 IIOReadProgressListener :

来自 JavaDoc:

ImageReader 实现使用的接口,用于通知调用者他们的图像和缩略图读取方法的进度。

此接口接收解码进度的一般指示(通过 imageProgress 和 thumbnailProgress 方法),以及指示整个图像何时更新的事件(通过 imageStarted、imageComplete、thumbnailStarted 和 thumbnailComplete 方法)。希望在像素更新发生时(例如,在渐进式解码期间)被通知的应用程序应提供 IIOReadUpdateListener。

于 2013-05-05T07:51:04.627 回答