如何模仿 Picasa 的低质量图像渲染以加快绘图速度

发布于 2024-09-06 10:38:48 字数 700 浏览 2 评论 0原文

我有一个所有者绘制的控件,在快速重绘(例如对象拖动、调整大小和绘制选择器方块)期间,性能是一个问题。我注意到其他几个应用程序,包括 Picasa,会在快速重绘场景中暂时绘制质量降低的图像,然后更新图像当用户界面“稳定下来”时,会出现更高质量的版本。

当发生许多快速重绘时,我应该(我可以吗?)生成较低质量的图像来绘制?是否有其他类似的策略,我可以采用来提高性能(或假装提高性能)。

额外信息:

这是一个类似表单设计器的应用程序,大量使用所有者绘图。它工作得很好,但当需要将三到四个以上的图像绘制到客户区域的矩形中时,它就会开始陷入困境。 (最终用户可以创建不同类型的元素,其中图像对绘图的影响最大。)

我使用 DrawImageUnscaled GDI+ 方法来绘制图像,这应该比 DrawImage 更有效,但性能分析显示 DrawImageUnscaled 仍然是瓶颈。我认为我唯一的办法就是想出聪明的方法来减少绘画。

PS 之前与此问题相关的问题为我赢得了风滚草徽章,因此我采取了另一种方法:如何提高 GDI 的 DrawImage(Unscaled) 的性能?

I have an owner-drawn control where performance is an issue during quick repaints such as object drags, resizing and painting the selector square. i have noticed that several other apps, including Picasa, will temporarily draw a reduced-quality image during fast repaint scenarios and then update the image with a higher-quality version when the UI "settles down."

How should I (can I?) produce a lower-quality image to paint when many quick redraws are taking place? Are there other strategies similar to this i can employ to increase performance (or fake increased performance.)

Extra Info:

This is a forms-designer-like application that makes heavy use of owner drawing. It works well but begins to bog down when more than three or four images need to be painted into rectangles in the client area. (End users are allowed to create different types of elements of which images take the heaviest toll on drawing.)

I am using the DrawImageUnscaled GDI+ method to draw images which is supposed to be much more efficient than DrawImage but performance profiling shows that DrawImageUnscaled is still the bottleneck. I think my only recourse is to come up with clever ways to draw less.

P.S. A previous question related to this issue earned me a Tumbleweed badge so i'm taking another approach: How to increase performance over GDI's DrawImage(Unscaled)?

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

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

发布评论

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

评论(1

花之痕靓丽 2024-09-13 10:38:49

等等——你在这里错过了一个容易实现的目标。在调整大小操作期间,这些可能根本没有真正重新绘制图像。他们可能会使用 StretchBlt 调整视频 RAM 中现有图像的大小,这可以通过视频驱动程序/硬件进行优化,速度非常非常快,比您“重新绘制质量降低的图像”还要快。

策略
-图像对象具有最后位置/大小(矩形)的成员变量
- 图像对象的重绘绘制全质量
-图像重绘更新最后位置
- 拖动期间,执行以下操作:
* StrechBlt 从上次位置/尺寸到当前位置/尺寸
* 更新最后的位置/尺寸
* 如果超过几秒。绘图,和/或自上次鼠标移动后 >.2 秒,调用重绘(不仅仅是无效 - 您现在想要它)以获得新的全质量图像。如果您检测到与其他对象的重叠,也会执行此操作(也会得到 StrechBlt'd)

我在执行类似操作的应用程序中使用的示例代码(类似放大的效果,可调整可能包含 100 个对象的窗口的大小 - 看起来像 iPad演示只是更平滑):

Declare Function StretchBlt Lib "gdi32.dll" _
   (ByVal hdcDest As IntPtr, _
    ByVal nXOriginDest As Integer, _
    ByVal nYOriginDest As Integer, _
    ByVal nWidthDest As Integer, _
    ByVal nHeightDest As Integer, _
    ByVal hdcSrc As IntPtr, _
    ByVal nXOriginSrc As Integer, _
    ByVal nYOriginSrc As Integer, _
    ByVal nWidthSrc As Integer, _
    ByVal nHeightSrc As Integer, _
    ByVal dwRop As Int32) As Boolean

    Using g As Graphics = f.pb.CreateGraphics
        ' parm of True says draw plain view - no text = looks bad Zooming.
        f.DrawAll(g, True)
        For i As Integer = iSteps To 1 Step -1
            Dim HDC1 As IntPtr = g.GetHdc
            Try
                ' Size of bite will not be right, but by re-adjusting 
                ' with each iteration, it will make it to full-screen.
                ' Looks as good as having it right to start with, only much easier.
                TopBite = objTop \ i
                BottomBite = h - ((h - objBottom) \ i)
                ' Stretch/move the stuff.
                StretchBlt(HDC1, 0, 0, w - LeftBite, h, _
                  HDC1, LeftBite, TopBite, w - LeftBite, BottomBite - TopBite, 13369376)
                ' Calculate where MyEntry would be after each stretch. Then the Bite 
                ' size calcs above will ensure its closer next time. 
                SimulateStretch(objTop, objBottom, TopBite, BottomBite, h)
            Finally
                g.ReleaseHdc(HDC1)
            End Try
            ' Clear exposed/invalid area to the right.
            g.FillRectangle(br, w - LeftBite, 0, LeftBite, h)
            ' Sleep will make Swells close in duration between small/big window.
            ' (Can I actually sleep this short of a time?)
            System.Threading.Thread.Sleep(5)
        Next
    End Using

当然,如果有人调整它的小图像然后备份,它将是超低质量和像素化的 - 所以你可以使用更智能的算法在鼠标拖动期间偶尔触发真正的绘制(如果不调整大小)。

注意具体细节将取决于具体的实现。您应该提供您的应用程序的更多详细信息,以便我可以正确使用它(它到底是什么样子?)我假设一个大方形用户控件带有许多所有者绘制的元素,所有元素一次均等地调整大小。如果您让它们从小处开始并调整大小以便它们开始重叠,则您必须在鼠标调整大小操作期间更频繁地定期进行完全重绘。

Wait - you missed out on a piece of low hanging fruit here. Those probably aren't really redrawing the image at all during re-size operations. They might be resizing the existing image in the video ram using StretchBlt - which can be optimized by the video driver/hardware to be very very fast, faster than you could ever 'redraw a reduced quality image.'

strategy:
-image objects have member variable for Last Position/Size (rect)
-repaint of image object draws full-quality
-repaint of image updates last position
-during dragging, do this:
* StrechBlt from Last Position/Size to Current position/Size
* Update Last Position/Size
* If more than a few secs. of drawing, and/or >.2s since last mouse move, call the repaint (not just invalidate - you want it NOW) to get a new full-quality image. Also do if you detect overlaps from other objects (will get StrechBlt'd too)

Sample code I use in an app that does something similar (a zoom-in like effect that sizes a window that could have 100s of objects - looks like an ipad demo only smoother):

Declare Function StretchBlt Lib "gdi32.dll" _
   (ByVal hdcDest As IntPtr, _
    ByVal nXOriginDest As Integer, _
    ByVal nYOriginDest As Integer, _
    ByVal nWidthDest As Integer, _
    ByVal nHeightDest As Integer, _
    ByVal hdcSrc As IntPtr, _
    ByVal nXOriginSrc As Integer, _
    ByVal nYOriginSrc As Integer, _
    ByVal nWidthSrc As Integer, _
    ByVal nHeightSrc As Integer, _
    ByVal dwRop As Int32) As Boolean

    Using g As Graphics = f.pb.CreateGraphics
        ' parm of True says draw plain view - no text = looks bad Zooming.
        f.DrawAll(g, True)
        For i As Integer = iSteps To 1 Step -1
            Dim HDC1 As IntPtr = g.GetHdc
            Try
                ' Size of bite will not be right, but by re-adjusting 
                ' with each iteration, it will make it to full-screen.
                ' Looks as good as having it right to start with, only much easier.
                TopBite = objTop \ i
                BottomBite = h - ((h - objBottom) \ i)
                ' Stretch/move the stuff.
                StretchBlt(HDC1, 0, 0, w - LeftBite, h, _
                  HDC1, LeftBite, TopBite, w - LeftBite, BottomBite - TopBite, 13369376)
                ' Calculate where MyEntry would be after each stretch. Then the Bite 
                ' size calcs above will ensure its closer next time. 
                SimulateStretch(objTop, objBottom, TopBite, BottomBite, h)
            Finally
                g.ReleaseHdc(HDC1)
            End Try
            ' Clear exposed/invalid area to the right.
            g.FillRectangle(br, w - LeftBite, 0, LeftBite, h)
            ' Sleep will make Swells close in duration between small/big window.
            ' (Can I actually sleep this short of a time?)
            System.Threading.Thread.Sleep(5)
        Next
    End Using

Of course if somebody sizes it itty-bitty image and then back up, it will be super low-quality and pixellated - so you can use a smarter algorythm to occasionally fire the real onpaint during mousedrag if not resizing.

note the nuts and bolts of this will depend on specific implementation. You should give more details of your app so I can get it right (what exactly does it look like?) I am assuming a big square usercontrol w/ many ownerdrawn elements, all resized at once equally. IF you have them start small and get resized so they start overlapping, you'll have to periodically do full redraws more often during mouse-resize operations.

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