如何使该图像缩放得更快?

发布于 2024-11-27 14:44:54 字数 2429 浏览 1 评论 0原文

我有一个轨迹栏,可以在移动图像时放大或缩小图像,但它缩放不顺畅,缩放到 200% 或更多时会出现瞬间延迟。

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
    zoom = trackBar1.Value;
    zoomValue = (float)(zoom / 10.0f);
    newBitmap = new Bitmap((int)(currWidth * zoomValue), (int)(currHeight * zoomValue));

    g = Graphics.FromImage(newBitmap);
    Matrix mx = new Matrix();
    mx.Scale(zoomValue, zoomValue);

    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.Transform = mx;
    g.DrawImage(currImage, new Rectangle(0, 0, currWidth, currHeight));
    g.Dispose();
    mx.Dispose();
    panel1.BackgroundImage = newBitmap;
}

我发现有人制作了一个用户控件 http://www.codeproject.com/KB/graphics/ YLScsImagePanel.aspx 缩放非常流畅。完全没有滞后。

private void trackBar1_Scroll(object sender, EventArgs e)
{
    imagePanel1.Zoom = trackBar1.Value * 0.02f;
}

这是来自自定义控件 ImagePanel.cs

public float Zoom
{
    get { return zoom; }
    set
    {
        if (value < 0.001f) value = 0.001f;
        zoom = value;

        displayScrollbar();
        setScrollbarValues();
        Invalidate();
    }
}

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    //draw image
    if(image!=null)
    {
        Rectangle srcRect,distRect;
        Point pt=new Point((int)(hScrollBar1.Value/zoom),(int)(vScrollBar1.Value/zoom));
        if (canvasSize.Width * zoom < viewRectWidth && canvasSize.Height * zoom < viewRectHeight)
            srcRect = new Rectangle(0, 0, canvasSize.Width, canvasSize.Height);  // view all image
        else srcRect = new Rectangle(pt, new Size((int)(viewRectWidth / zoom), (int)(viewRectHeight / zoom))); // view a portion of image

        distRect=new Rectangle((int)(-srcRect.Width/2),-srcRect.Height/2,srcRect.Width,srcRect.Height); // the center of apparent image is on origin

        Matrix mx=new Matrix(); // create an identity matrix
        mx.Scale(zoom,zoom); // zoom image
        mx.Translate(viewRectWidth/2.0f,viewRectHeight/2.0f, MatrixOrder.Append); // move image to view window center

        Graphics g=e.Graphics;
        g.InterpolationMode=interMode;
        g.Transform=mx;
        g.DrawImage(image,distRect,srcRect, GraphicsUnit.Pixel);
    }

}

是因为我每次滞后时都会创建一个新的位图吗?我怎样才能让它像这样平滑地缩放?

I have a trackbar that zooms in or zooms out an image as I move it but it doesn't zoom smoothly, with a split second lag for zoom of 200% or more.

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
    zoom = trackBar1.Value;
    zoomValue = (float)(zoom / 10.0f);
    newBitmap = new Bitmap((int)(currWidth * zoomValue), (int)(currHeight * zoomValue));

    g = Graphics.FromImage(newBitmap);
    Matrix mx = new Matrix();
    mx.Scale(zoomValue, zoomValue);

    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.Transform = mx;
    g.DrawImage(currImage, new Rectangle(0, 0, currWidth, currHeight));
    g.Dispose();
    mx.Dispose();
    panel1.BackgroundImage = newBitmap;
}

I found a user control someone made http://www.codeproject.com/KB/graphics/YLScsImagePanel.aspx that zooms very smoothly. There is no lag at all.

private void trackBar1_Scroll(object sender, EventArgs e)
{
    imagePanel1.Zoom = trackBar1.Value * 0.02f;
}

This is from the custom control ImagePanel.cs

public float Zoom
{
    get { return zoom; }
    set
    {
        if (value < 0.001f) value = 0.001f;
        zoom = value;

        displayScrollbar();
        setScrollbarValues();
        Invalidate();
    }
}

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    //draw image
    if(image!=null)
    {
        Rectangle srcRect,distRect;
        Point pt=new Point((int)(hScrollBar1.Value/zoom),(int)(vScrollBar1.Value/zoom));
        if (canvasSize.Width * zoom < viewRectWidth && canvasSize.Height * zoom < viewRectHeight)
            srcRect = new Rectangle(0, 0, canvasSize.Width, canvasSize.Height);  // view all image
        else srcRect = new Rectangle(pt, new Size((int)(viewRectWidth / zoom), (int)(viewRectHeight / zoom))); // view a portion of image

        distRect=new Rectangle((int)(-srcRect.Width/2),-srcRect.Height/2,srcRect.Width,srcRect.Height); // the center of apparent image is on origin

        Matrix mx=new Matrix(); // create an identity matrix
        mx.Scale(zoom,zoom); // zoom image
        mx.Translate(viewRectWidth/2.0f,viewRectHeight/2.0f, MatrixOrder.Append); // move image to view window center

        Graphics g=e.Graphics;
        g.InterpolationMode=interMode;
        g.Transform=mx;
        g.DrawImage(image,distRect,srcRect, GraphicsUnit.Pixel);
    }

}

Is it because I'm creating a new bitmap each time that it lags? How can I make it zoom smoothly like this one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

铜锣湾横着走 2024-12-04 14:44:54

正如 @CodingBarfield 提到的,在 trackBar1_ValueChanged() 方法中计算缩放图像并不是一个好主意。原因是,如果缩放得太快,您仍然会在每个中间步骤中计算重新缩放的图像(即使是那些步骤,也永远不会显示)。因此,将方法更改为如下所示:

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
    panel1.Invalidate();
}

并将缩放本身放入 OnPaint() 方法中,如下所示:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    zoom = trackBar1.Value;
    if (lastZoom != zoom)
    {
        // the zoom has changed, clear the cache
        lastZoom = zoom;
        imageCache = null;
    }

    if (imageCache == null && image != null)
    {
        // compute scaled image
        imageCache = scaleImage(image, zoom);
    }

    //draw image
    if(image!=null)
    {
        ...
    }
}

OnPaint() 方法中的缩放不是100% 干净的解决方案,因为它仍然会有点阻碍你的 GUI 线程。更好的选择是使用后台线程,但我认为这应该足够了,它可以节省您一些编码时间。

此外,您还可以通过仅缩放所需图像的部分来获得一些额外的性能增益。这种技术将为您节省缩放的平方,因此缩放越大,节省的计算量就越多。

另一种选择是选择一些计算成本较低的插值模式。或者您甚至可以计算一些低质量的近似值,显示它,然后使用后台线程计算一些质量更好的图像。

或者,也许您可​​以扔掉所有这些代码,只修改一下 CodePlex 示例以满足您的需求:)。

希望这有帮助。

as @CodingBarfield mentioned, it is not a good idea to compute the scaled image in the trackBar1_ValueChanged() method. The reason is that you if you zoom too fast, you would still compute the rescaled image in every intermediate step (even those steps, that would be never displayed). So change the method to look like this:

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
    panel1.Invalidate();
}

And put the scaling itself to the OnPaint() method to look something like this:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    zoom = trackBar1.Value;
    if (lastZoom != zoom)
    {
        // the zoom has changed, clear the cache
        lastZoom = zoom;
        imageCache = null;
    }

    if (imageCache == null && image != null)
    {
        // compute scaled image
        imageCache = scaleImage(image, zoom);
    }

    //draw image
    if(image!=null)
    {
        ...
    }
}

The scaling in OnPaint() method is not a 100% clean solution, because it can still a bit hold your GUI thread back. Better option would be to use a background thread, but I think this should be enough and it can save you some coding time.

Also you can obtain some additional performance gain by scaling just the part of the image you need. This technique will save you square of the zoom, so the large the zoom is the more computations are saved.

Another option is to choose some less computationally expensive interpolation mode. Or you can even compute some low quality approximation, display it, and then compute some better quality image using background thread.

Or maybe you can throw all this code away and just a bit modify the CodePlex example to fit your needs :).

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文