简体   繁体   English

使用GDI +使用不同颜色绘制线条的快捷方法?

[英]Fast way to draw lines using different Color using GDI+?

I have an dynamic List of Point, new Point can be added at any time. 我有一个动态List of Point,可以随时添加新Point。 I want to draw lines to connect them using different color. 我想绘制线条以使用不同的颜色连接它们。 Color is based on the index of those points. 颜色基于这些点的索引。 Here is the code: 这是代码:

    private List<Point> _points;
    private static Pen pen1 = new Pen(Color.Red, 10);
    private static Pen pen2 = new Pen(Color.Yellow, 10);
    private static Pen pen3 = new Pen(Color.Blue, 10);
    private static Pen pen4 = new Pen(Color.Green, 10);

    private void Init()
    {
        // use fixed 80 for simpicity
        _points = new List<Point>(80);

        for (int i = 0; i < 80; i++)
        {
            _points.Add(new Point(30 + i * 10, 30));
        }
    }

    private void DrawLinesNormal(PaintEventArgs e)
    {
        for (int i = 0; i < _points.Count-1; i++)
        {
            if (i < 20)
                e.Graphics.DrawLine(pen1, _points[i], _points[i + 1]);
            else if (i < 40)
                e.Graphics.DrawLine(pen2, _points[i], _points[i + 1]);
            else if (i < 60)
                e.Graphics.DrawLine(pen3, _points[i], _points[i + 1]);
            else
                e.Graphics.DrawLine(pen4, _points[i], _points[i + 1]);
        }
    }

I find this method is not fast enough when I have new points coming in at a high speed. 当我有新的高速进入时,我发现这种方法不够快。 Is there any way to make it faster? 有没有办法让它更快? I did some research and someone said using GraphicsPath could be faster, but how? 我做了一些研究,有人说使用GraphicsPath可能会更快,但如何?

[UPDATE] I collect some possible optimizations: [更新]我收集了一些可能的优化:

  1. Using GrahpicsPath, Original Question 使用GrahpicsPath, 原始问题
  2. Change Graphics quality ( such as SmoothingMode/PixelOffsetMode...), also call SetClip to specify the only necessary region to render. 更改图形质量(例如SmoothingMode / PixelOffsetMode ...),也调用SetClip指定要渲染的唯一必要区域。

You won't be able to squeeze much more speed out of that code without losing quality or changing to a faster renderer (GDI, OpenGL, DirectX). 在不降低质量或更改为更快的渲染器(GDI,OpenGL,DirectX)的情况下,您将无法从代码中挤出更多的速度。 But GDI will often be quite a bit faster (maybe 2x), and DirectX/OpenGL can be much faster (maybe 10x), depending on what you're drawing. 但是GDI通常会快得多(可能是2倍),而DirectX / OpenGL可以更快(可能是10倍),这取决于你绘制的内容。

The idea of using a Path is that you batch many (in your example, 20) lines into a single method call, rather than calling DrawLine 20 times. 使用Path的想法是将许多(在您的示例中为20行)行批处理为单个方法调用,而不是将DrawLine调用20次。 This will only benefit you if you can arrange the incoming data into the correct list-of-points format for the drawing routine. 如果您可以将传入数据排列为绘图例程的正确列表格式,这将使您受益。 Otherwise, you will have to copy the points into the correct data structure and this will waste a lot of the time that you are gaining by batching into a path. 否则,您将必须将点复制到正确的数据结构中,这将浪费您通过批处理路径获得的大量时间。 In the case of DrawPath, you may have to create a GraphicsPath from an array of points, which may result in no time saved. 对于DrawPath,您可能必须从点数组创建GraphicsPath,这可能导致没有时间保存。 But if you have to draw the same path more than once, you can cache it, and you may then see a net benefit. 但是如果你不得不多次绘制相同的路径,你可以缓存它,然后你可以看到净收益。

If new points are added to the list, but old ones are not removed (ie you are always just adding new lines to the display) then you would be able to use an offscreen bitmap to store the lines rendered so far. 如果将新点添加到列表中,但不删除旧点(即,您始终只是向显示添加新行),那么您将能够使用屏幕外位图来存储到目前为止渲染的线。 That way each time a point is added, you draw one line, rather than drawing all 80 lines every time. 这样,每次添加一个点时,都会绘制一条线,而不是每次都绘制所有80条线。

It all depends on exactly what you're trying to do. 这完全取决于你想要做什么。

Doesn't really help to improve performance, but i would put the pens also into a list and writing all this lines in this way: 没有真正帮助提高性能,但我会把笔也放到一个列表中并以这种方式写下所有这些行:

int ratio = _points.Count / _pens.Count;

for (int i = 0; i < _points.Count - 1; i++)
{
    e.Graphics.DrawLine(_pens[i / ratio], _points[i], _points[i + 1]);
}

This is about as fast as you're going to get with System.Drawing. 这与您使用System.Drawing的速度差不多。 You might see a bit of gain using Graphics.DrawLines() , but you'd need to format your data differently to get the advantage of drawing a bunch of lines at once with the same pen. 您可能会看到使用Graphics.DrawLines()获得一些收益,但您需要以不同方式格式化数据,以便使用相同的笔一次性绘制一堆线。 I seriously doubt GraphicsPath will be faster. 我非常怀疑GraphicsPath会更快。

One sure way to improve speed is to reduce the quality of the output. 提高速度的一个可靠方法是降低输出质量。 Set Graphics.InterpolationMode to InterpolationMode.Low , Graphics.CompositingQuality to CompositingQuality.HighSpeed , Graphics.SmoothingMode to SmoothingMode.HighSpeed , Graphics.PixelOffsetMode to PixelOffsetMode.HighSpeed and Graphics.CompositingMode to CompositingMode.SourceCopy . 设置Graphics.InterpolationModeInterpolationMode.LowGraphics.CompositingQualityCompositingQuality.HighSpeedGraphics.SmoothingModeSmoothingMode.HighSpeedGraphics.PixelOffsetModePixelOffsetMode.HighSpeedGraphics.CompositingModeCompositingMode.SourceCopy

I remember a speed test once where someone compared Graphics to P/Invoke into GDI routines, and was quite surprised by the much faster P/Invoke speeds. 我记得一次速度测试,有人将Graphics与P / Invoke比作GDI例程,并且对P / Invoke速度快得多,我感到非常惊讶。 You might check that out. 你可能会检查出来。 I'll see if I can find that comparison... Apparently this was for the Compact Framework, so it likely doesn't hold for a PC. 我会看看我是否能找到这种比较...... 显然这是针对Compact Framework的,因此很可能不适用于PC。

The other way to go is to use Direct2D, which can be faster yet than GDI, if you have the right hardware. 另一种方法是使用Direct2D,如果你有合适的硬件,它可以比GDI更快。

Too late, but possibly somebody still need a solution. 太晚了,但可能还有人需要解决方案。

I've created small library GLGDI+ with similiar (but not full/equal) GDI+ syntax, which run upon OpenTK: http://code.google.com/p/glgdiplus/ 我用类似的(但不是完全/相等的)GDI +语法创建了小型库GLGDI +,它运行在OpenTK上: http//code.google.com/p/glgdiplus/

I'm not sure about stability, it has some issues with DrawString (problem with TextPrint from OpenTK). 我不确定稳定性,它与DrawString有一些问题(来自OpenTK的TextPrint问题)。 But if you need performance boost for your utility (like level editor in my case) it can be solution. 但是如果你需要为你的实用程序提升性能(比如我的情况下的级别编辑器),它可以是解决方案。

You might wanna look into the Brush object, and it's true that you won't get near real-time performance out of a GDI+ program, but you can easily maintain a decent fps as long as the geometry and number of objects stay within reasonable bounds. 您可能希望查看Brush对象,并且您确实无法通过GDI +程序获得接近实时性能,但只要对象的几何和数量保持在合理的范围内,您就可以轻松维护体面的fps。 。 As for line drawing, I don't see why not. 至于画线,我不明白为什么不。

But if you reach the point where you doing what you think is optimal, and all that is, drawing lines.. you should consider a different graphics stack, and if you like .NET but have issues with unmanaged APIs like OpenGL and DirectX, go with WPF or Silverlight, it's quite powerful. 但是如果你达到了你认为最佳的点,那就是画线......你应该考虑一个不同的图形堆栈,如果你喜欢.NET但是有非托管API的问题,比如OpenGL和DirectX,那就去吧使用WPF或Silverlight,它非常强大。

Anyway, you could try setting up a System.Drawing.Drawing2D.GraphicsPath and then using a System.Drawing.Drawing2D.PathGradientBrush to a apply the colors this way. 无论如何,您可以尝试设置System.Drawing.Drawing2D.GraphicsPath,然后使用System.Drawing.Drawing2D.PathGradientBrush以这种方式应用颜色。 That's a single buffered draw call and if you can't get enough performance out of that. 这是一个单缓冲的绘制调用,如果你无法获得足够的性能。 You'll have to go with something other entirely than GDI+ 除了GDI +,你必须完全采用其他方法

Not GDI(+) at all, but a completely different way to tackle this could be to work with a block of memory, draw your lines into there, convert it to a Bitmap object to instantly paint where you need to show your lines. 根本不是GDI(+),但解决这个问题的完全不同的方法是使用一块内存,将线条绘制到那里,将其转换为Bitmap对象,以便立即绘制您需要显示线条的位置。

Of course this hinges in the extreme on fast ways to 当然,这在快速的方式上取决于极端

  • draw lines of given color in the memory representation of choice and 在所选择的内存表示中绘制给定颜色的线条
  • convert that to the Bitmap to show. 将其转换为要显示的Bitmap

Not in the .NET Framework, I think, but perhaps in a third party library? 我想,不是在.NET Framework中,而是在第三方库中? Isn't there a bitmap writer of sorts in Silverlight for stuff like this? 对于像这样的东西,Silverlight中没有类似的位图编写器吗? (Not into Silverlight myself that much yet...) (我自己还没有进入Silverlight ......)

At least it might be an out of the box way to approach this. 至少它可能是开箱即用的方法。 Hope it helps. 希望能帮助到你。

I think you have to dispose pen object and e.Graphics object after drawing. 我认为你必须在绘图后处理笔对象和e.Graphics对象。 One more thing it is better if you write your drawLine code inside onPaint(). 如果你在onPaint()中编写drawLine代码,还有一件事情会更好。

 just override onPaint() method it support better drawing and fast too.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM