【问题标题】:How to prevent graphical stutter when scrolling a large zoomed out picture滚动缩小的大图片时如何防止图形卡顿
【发布时间】:2014-05-19 08:46:27
【问题描述】:

我有一张大的 TIFF 图片(5.9 MB,13k X 16k 分辨率),用户将其加载到可滚动面板中,然后他可以放大/缩小、滚动和标记点、区域等。

对于可滚动的双缓冲面板,我使用的是 Bob Powell's awesome ZoomPicBox 的修改 面板仅显示当前视图中的图片部分。

缩小时滚动图像时出现卡顿(即使interpolationMode设置为低)。

有什么可以做的吗(最好没有硬件加速)?

面板的绘制事件:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        if (_image == null)
        {
            base.OnPaintBackground(e);
            return;
        }

        //scale
        System.Drawing.Drawing2D.Matrix ScaleMat = new System.Drawing.Drawing2D.Matrix(_zoom, 0, 0, _zoom, 0, 0);
        //move to position of scrollbas
        ScaleMat.Translate(this.AutoScrollPosition.X / (_zoom), this.AutoScrollPosition.Y / (_zoom));


        e.Graphics.Transform = ScaleMat;
        e.Graphics.InterpolationMode = _interpolationMode;

        e.Graphics.DrawImage(_image, new Rectangle(0, 0, _image.Width, _image.Height), 0, 0, _image.Width, _image.Height, GraphicsUnit.Pixel);

        
        base.OnPaint(e);
    }

* _zoom ,_image 和 _interpolationMode 是控件的私有字段。

构造函数:

 public PicBoxPlus()
        {
            MouseMove += PicBoxPlus_MouseMove;
            KeyDown += PicBoxPlus_KeyDown;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);

            this.AutoScroll = true;
        }

然后我尝试实现 Sinatr 的代码,但出现了问题,因为我得到的只是一张黑色图像(大小合适)。有人知道可能出了什么问题吗?

新的绘画事件:

 protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            if (mCachedImage == null)
            {
                base.OnPaintBackground(e);
                return;
            }

            //scale
            System.Drawing.Drawing2D.Matrix ScaleMat = new System.Drawing.Drawing2D.Matrix(mZoom, 0, 0, mZoom, 0, 0);
            //move to position of scrollbas
            ScaleMat.Translate(this.AutoScrollPosition.X / (mZoom), this.AutoScrollPosition.Y / (mZoom));

            try
            {
                if (mCachedImage == null)
                {
                    mCachedImage = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
                    using (var cacheGraphics = Graphics.FromImage(mCachedImage))
                    {
                        cacheGraphics.Transform = ScaleMat;
                        cacheGraphics.InterpolationMode = _interpolationMode;
                        cacheGraphics.DrawImage(mCachedImage, new Rectangle(0, 0, mCachedImage.Width, mCachedImage.Height), 0, 0, mCachedImage.Width, mCachedImage.Height, GraphicsUnit.Pixel);

                    }

                    e.Graphics.DrawImage(mCachedImage, Point.Empty);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
           
            base.OnPaint(e);
        }

图像和缩放属性:

public Bitmap Image
    {
        get { return mCachedImage; }
        set
        {
            mCachedImage = value;
            UpdateScaleFactor();
            this.Invalidate();
        }
    }

public Single Zoom
{
    get { return mZoom; }
    set
    {
        if (value <= 0||value < 0.001)
        {
            value = 0.001f;
        }

        mZoom = value;
        UpdateScaleFactor();
        ResetCache(); // Sinatr's function
        this.Invalidate();
    }
}

从主窗体加载图像:

panelMap.Image = (Bitmap)Image.FromFile("pic.tiff");

【问题讨论】:

  • 如果重绘代价高昂(发生stutter),那么您必须对其进行优化。例如,尝试缓存转换后的图像(您可以从位图创建Graphics)并在大小/缩放更改时销毁缓存。
  • 能否提供一个图片缓存的例子?

标签: c# image graphics gdi+


【解决方案1】:

未经测试,但应该给出一个想法。

Bitmap _cached = null;

override void OnPaint(PaintEventArgs e)
{
    if(_cached == null)
    {
        _cached = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
        using(var graphics = Graphics.FromImage(_cached)
        {
             // draw into this graphics once -> it will be cached in _cached bitmap
        }
    }
    e.Graphics.DrawImage(_cached, Point.Empty);
}

// call this if _zoom or ClientSize is changed
void ResetCache()
{
    _cache = null;
    this.Invalidate(); // mandatory for _zoom change
}

另外,我不知道如何展示放大后的图片,但通常有一个偏移,以便您可以移动(平移)图像。

【讨论】:

  • 感谢您提供示例!它必须是一个bitmpap吗?我想我将主要使用 .tiff 和 .png 类型的图像
  • 嗯...这似乎对我不起作用。加载图片后面板为空,但它确实改变了大小......
  • 我将 ResetCache() 函数移至 Zoom 属性。现在我只得到一个大小合适但黑色的面板
  • 我已将其添加到原帖中。
  • 为什么画完要打base.OnPaint()
猜你喜欢
  • 2019-08-23
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 2021-01-10
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 2011-06-06
相关资源
最近更新 更多