【发布时间】:2012-11-17 09:07:13
【问题描述】:
我正在编写一个显示地图的程序,并在其顶部显示相机位置及其观察方向的另一层。地图本身可以缩放和平移。问题是地图文件很大,缩放不顺畅。
我创建了class ZoomablePictureBox : PictureBox 来添加缩放和平移功能。我尝试了不同的方法,来自这个论坛和其他论坛,用于缩放和平移,最终得到以下结果,触发 ZoomablePictureBox 的 OnPaint 事件:
private void DrawImgZoomed(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (imgZoomed != null)
e.Graphics.DrawImage(imgZoomed, new Rectangle(-ShiftX, -ShiftY, imgZoomed.Width, imgZoomed.Height), 0, 0, imgZoomed.Width, imgZoomed.Height, GraphicsUnit.Pixel);
}
ShiftX 和 ShiftY 提供正确的地图平移(计算与此问题无关)。
imgZoomed 是每次缩放变化时在 BackgroundWorker 中计算的原始地图的缩放版本:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
Bitmap workerImage = e.Argument as Bitmap;
Bitmap result;
result = new Bitmap(workerImage, new Size((int)(workerImage.Width * Zoom), (int)(workerImage.Height * Zoom)));
e.Result = result;
}
所以当前的方法是,每次用户滚动鼠标滚轮时,都会根据当前缩放计算新的imgZoomed。地图大小约为 30 MB,这可能需要 0.5 秒,这很烦人,但平移运行平稳。
我意识到这可能不是最好的主意。在以前的方法中,我没有在每次滚动鼠标时创建缩放图像副本,而是这样做:
e.Graphics.DrawImage(Image, new Rectangle(-ShiftX, -ShiftY, (int)(this._image.Width * Zoom), (int)(this._image.Height * Zoom)), 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel);
缩放更平滑,因为据我了解,它只是拉伸了原始图像。另一方面,平移正在大量跳过。
我没想到:
- 为每次放大内存/硬盘驱动器创建原始地图副本 - 这会占用太多内存/硬盘空间
- 为下一个/实际/上一个缩放创建原始地图的副本,以便我 有更多时间来计算下一步 - 如果用户 一次滚动不止一个步骤
我还尝试了矩阵变换 - 没有真正的性能提升,而且计算 pan 真的很痛苦。
我在这里兜圈子,不知道该怎么做。如果我在默认的 Windows 图片查看器中打开地图,则缩放和平移很流畅。他们是怎么做到的?
如何同时实现平滑的缩放和平移?
【问题讨论】:
-
我最近实现了类似的东西,经过多次测试,到目前为止我获得的最流畅的性能是使用
StretchBlt和缓存的Graphics和HBitmap对象实现的。即使在 7000X7000 的图像上,这也帮助我实现了超级流畅的显示。