C# 可能的GDI+抽绳优化思考

C# 可能的GDI+抽绳优化思考,c#,optimization,interop,system.drawing,C#,Optimization,Interop,System.drawing,我试图从c GDI+DrawLines函数中获得更高的性能。当我在代码上运行探查器时,我看到DrawLines函数中花费的几乎一半时间是准备将点数组发送到本机GDI+dll。这似乎是一个很大的开销,我想知道是否有人能想出一种比System.Drawing中DrawLines函数的本机实现更有效的方法来与DrawLines函数交互 以下是本机Systemm.Drawing函数: public void DrawLines(Pen pen, PointF[] points) { if (pe

我试图从c GDI+DrawLines函数中获得更高的性能。当我在代码上运行探查器时,我看到DrawLines函数中花费的几乎一半时间是准备将点数组发送到本机GDI+dll。这似乎是一个很大的开销,我想知道是否有人能想出一种比System.Drawing中DrawLines函数的本机实现更有效的方法来与DrawLines函数交互

以下是本机Systemm.Drawing函数:

public void DrawLines(Pen pen, PointF[] points)
{
    if (pen == null)
    {
        throw new ArgumentNullException("pen");
    }
    if (points == null)
    {
        throw new ArgumentNullException("points");
    }
    IntPtr handle = SafeNativeMethods.Gdip.ConvertPointToMemory(points);
    int status = SafeNativeMethods.Gdip.GdipDrawLines(new HandleRef(this,this.NativeGraphics), new HandleRef(pen, pen.NativePen), new   HandleRef(this, handle),     points.Length);
Marshal.FreeHGlobal(handle);
    this.CheckErrorStatus(status);
}


如果你想在Windows上提高C 2D绘图操作的性能,你应该考虑。

< P>这个方法的引线在NET-GDI+API中也有一些不幸和其他方法。首先,它只需要一个数组,这意味着点数必须与数组的大小完全匹配;如果您不确定在准备点时将有多少点,则必须调用Array.Resize以复制数据。其次,DrawLine方法中的第一个操作是复制点-为什么不将原始数据传递给GDI+?实际上,数据在到达GDI+之前被复制了两次。 对此可以做些什么:

使用P/Invoke从C使用。 使用本地C++接口,例如使用C++和CLI与C接口。 第一个想法可能是这样的:

public void DrawLines(System.Drawing.Color color, ref System.Drawing.Point[] points, int pointsCount)
    {
        IntPtr pen = IntPtr.Zero;
        int status = GdipCreatePen1(
                                color.ToArgb(),
                                1,
                                (int)GraphicsUnit.World,
                                out pen);
        unsafe
        {
            fixed (Point* pointerPoints = points)
            {
                status = GdipDrawLinesI(new HandleRef(this, this.handleGraphics), new HandleRef(this, pen), (IntPtr)pointerPoints, pointsCount);
            }
        }

        status = GdipDeletePen(new HandleRef(this, pen));
    }

    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] 
    private static extern int GdipDrawLinesI(HandleRef graphics, HandleRef pen, IntPtr points, int count);        
    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true)]
    private static extern int GdipDeletePen(HandleRef pen);
    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true)]
    private static extern int GdipCreatePen1(int argb, float width, int unit, out IntPtr pen);
Type type = typeof(System.Drawing.Font);
System.Reflection.PropertyInfo propInfoNativeFontHandle = type.GetProperty("NativeFont", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Drawing.Font font = ...
IntPtr nativeHandle = propInfoNativeFontHandle.GetValue(font, null)
顺便说一句,通过使用反射可以访问.NET-GDI+对象中的本机句柄。当然,这是未记录的,您需要访问私有方法。对于System.Drawing.Font对象,这将类似于:

public void DrawLines(System.Drawing.Color color, ref System.Drawing.Point[] points, int pointsCount)
    {
        IntPtr pen = IntPtr.Zero;
        int status = GdipCreatePen1(
                                color.ToArgb(),
                                1,
                                (int)GraphicsUnit.World,
                                out pen);
        unsafe
        {
            fixed (Point* pointerPoints = points)
            {
                status = GdipDrawLinesI(new HandleRef(this, this.handleGraphics), new HandleRef(this, pen), (IntPtr)pointerPoints, pointsCount);
            }
        }

        status = GdipDeletePen(new HandleRef(this, pen));
    }

    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] 
    private static extern int GdipDrawLinesI(HandleRef graphics, HandleRef pen, IntPtr points, int count);        
    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true)]
    private static extern int GdipDeletePen(HandleRef pen);
    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true)]
    private static extern int GdipCreatePen1(int argb, float width, int unit, out IntPtr pen);
Type type = typeof(System.Drawing.Font);
System.Reflection.PropertyInfo propInfoNativeFontHandle = type.GetProperty("NativeFont", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Drawing.Font font = ...
IntPtr nativeHandle = propInfoNativeFontHandle.GetValue(font, null)

谢谢Direct2D是未来的发展方向,但是现在我仍然坚持使用GDI+,这并不是很糟糕。如果c包装器没有这样的开销,可能会更好,因此我的问题是。有点离题,但值得指出的是,您可以使用Windows API代码包访问Direct2D接口。