如何在C#/ WPF / WinForms中将WMF渲染到BitMap时启用消除锯齿function?

这样做时为什么线路等不会被消除锯齿?

using (var myGraphics = Graphics.FromImage(bitmap)) { myGraphics.CompositingQuality = CompositingQuality.HighQuality; myGraphics.SmoothingMode = SmoothingMode.HighQuality; myGraphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; myGraphics.Clear(backgroundColor); myGraphics.EnumerateMetafile(m_metafile, new Point(0, 0), m_metafileDelegate); } 

委托函数如下所示:

 private bool MetafileCallback(EmfPlusRecordType recordType, int flags, int dataSize, IntPtr data, PlayRecordCallback callbackData) { byte[] dataArray = null; if (data != IntPtr.Zero) { // Copy the unmanaged record to a managed byte buffer // that can be used by PlayRecord. dataArray = new byte[dataSize]; Marshal.Copy(data, dataArray, 0, dataSize); } m_metafile.PlayRecord(recordType, flags, dataSize, dataArray); return true; } 

我是否需要覆盖特定类型的PlayRecord才能获得抗锯齿function?

如果有任何帮助,WMF来自AutoCAD。

这在使用WMF图元文件的GDI +中是不可能的,但它与EMF Plus一起使用。 您可以在源头转换为EMF Plus,也可以使用记录不良的GDI +方法即时转换(见下文)。

GDI(不是GDI +)渲染WMF文件而不使用其下面的GDI + Graphics对象的任何合成,它只是直接GDI调用的枚举。 请参阅此问题了解更多信息,但所有答案都说同样的事情 。

如果您可以将文件转换为EMF Plus,则将使用GDI +方法呈现内容,并使用GDI +合成(包括抗锯齿)。 如果您已经在使用WPF,那么您也可以考虑导出到XPS,哪个WPF可以呈现抗锯齿。

如果你不能在源代码转换,你可以从C#调用GDI +方法,但它不优雅。 您需要访问System.Drawing类使用的本机句柄:

 [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] internal static extern int GdipConvertToEmfPlus(HandleRef graphics, HandleRef metafile, out Boolean conversionSuccess, EmfType emfType, [MarshalAsAttribute(UnmanagedType.LPWStr)] String description, out IntPtr convertedMetafile); 

您可以使用与以下代码类似的代码:

 using (var graphics = Graphics.FromImage(bmp)) using (var metafile = Metafile.FromFile(@"drawing.wmf")) using (var imageAttr = new ImageAttributes()) { graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; var metafileHandleField = typeof(Metafile).GetField("nativeImage", BindingFlags.Instance | BindingFlags.NonPublic); var imageAttributesHandleField = typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.Instance | BindingFlags.NonPublic); var graphicsHandleProperty = typeof(Graphics).GetProperty("NativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic); var setNativeImage = typeof(Image).GetMethod("SetNativeImage", BindingFlags.Instance | BindingFlags.NonPublic); IntPtr mf = (IntPtr)metafileHandleField.GetValue(metafile); IntPtr ia = (IntPtr)imageAttributesHandleField.GetValue(imageAttr); IntPtr g = (IntPtr)graphicsHandleProperty.GetValue(graphics); Boolean isSuccess; IntPtr emfPlusHandle; var status = GdipConvertToEmfPlus(new HandleRef(graphics, g), new HandleRef(metafile, mf), out isSuccess, EmfType.EmfPlusOnly, "", out emfPlusHandle); if (status != 0) { throw new Exception("Can't convert"); } using (var emfPlus = (Metafile)System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject(typeof(Metafile))) { setNativeImage.Invoke(emfPlus, new object[] { emfPlusHandle }); // use EnumerateMetafile on emfPlus as per your example code or save it: emfPlus.Save(@"drawing.emf"); } } 

这是LinqPad的一个工作示例 。 它将WMF文件(drawing.wmf)转换为EMF Plus元文件,并将其显示在结果面板中。

Paint中的WMF文件: 没有抗锯齿的WMF文件

在Paint中转换的EMF +文件: 具有抗锯齿功能的EMF +文件


为了完整起见,上面的GdipConvertToEmfPlus方法是GDI +的“ 平面API ”的一部分。 它最初的目的是只提供GDI + C ++类。 使用此方法的C ++ API称为Metafile.ConvertToEmfPlus