如何进行平滑的图像缩放和平移?

时间:2012-11-29 10:07:13

标签: c# winforms zoom

我正在编写一个显示地图的程序,并在其上面显示另一个图层,其中显示了摄像机的位置及其查看方向。地图本身可以缩放和平移。问题是地图文件的大小很大,缩放不顺畅。

我创建了class ZoomablePictureBox : PictureBox来添加缩放和平移功能。我尝试了不同的方法,从这个和其他论坛,进行缩放和平移,最后得到以下内容,触发OnPaint事件ZoomablePictureBox

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

变焦更平滑,因为根据我的理解,它只是拉伸了原始图像。另一方面,平移正在大量跳过。

我想:

  • 为内存中/硬盘上的每个缩放创建orignial地图的副本 - 它将占用太多的内存/硬盘空间
  • 为下一个/实际/以前的缩放创建orignial地图的副本,所以我 有更多的时间来计算下一步 - 如果用户没有帮助 一次滚动多个步骤

我也试过矩阵变换 - 没有真正的性能提升,计算平移是一个真正的痛苦。

我在这里跑圈子,不知道怎么做。如果我在默认的Windows图片浏览器中打开地图,则缩放和平移是平滑的。他们是如何做到的?

我以何种方式同时实现平滑缩放和平移?

1 个答案:

答案 0 :(得分:1)

对不起,这太长了,我只留下了必要的部分。

大部分p / invoke内容取自pinvoke.net

我在大图像中平滑平移的解决方案涉及使用StretchBlt gdi方法而不是Graphics.DrawImage。我创建了一个静态类,它将所有本机blitting操作分组。

另一件有用的事情是缓存HBitmap的{​​{1}}和Graphics个对象。

Bitmap