c# – 可能的GDI DrawLines优化思考
作者:互联网
我试图从c#GDI DrawLines函数中获得更多性能.当我在代码上运行一个分析器时,我发现在DrawLines函数中花费的时间几乎有一半是准备将点数组发送到本机GDI dll.这似乎是一个很大的开销,我想知道是否有人能够提出一种更有效的方式与DrawLines函数交互,而不是在System.Drawing中使用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);
}
internal static IntPtr ConvertPointToMemory(PointF[] points)
{
if (points == null)
{
throw new ArgumentNullException("points");
}
int num2 = Marshal.SizeOf(new GPPOINTF().GetType());
int length = points.Length;
IntPtr ptr = Marshal.AllocHGlobal((int) (length * num2));
for (int i = 0; i < length; i++)
{
Marshal.StructureToPtr(new GPPOINTF(points[i]), (IntPtr) (((long) ptr) + (i * num2)), false);
}
return ptr;
}
解决方法:
这种方法“DrawLines”有点不幸(以及.NET-GDI -API中的其他几种方法).首先,它只需要一个数组,这意味着点的数量必须与数组的大小完全匹配;如果您不确定在准备点时将获得多少点,则必须调用Array.Resize来复制数据.其次,DrawLine方法中的第一个动作是复制点 – 为什么不将原始数据传递给GDI?实际上,数据在到达GDI之前会被复制两次.
可以做些什么:
>使用C#中的GDI+ Flat API(使用P / Invoke).
>使用(本机)C API](例如,使用C/C++LI与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);
顺便说一句 – 通过使用反射可以访问.NET-GDI对象中的本机句柄(当然,这是未记录的,您需要访问私有方法).对于System.Drawing.Font对象,这将看起来像这样:
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)
标签:c,optimization,interop,system-drawing 来源: https://codeday.me/bug/20190626/1298294.html