使用WMF元文件在GDI+中无法实现此功能,但使用EMF Plus可以。您可以在源处将其转换为EMF Plus,也可以使用文档不全的GDI+方法进行即时转换(请参见下文)。
GDI(而不是GDI+)呈现WMF文件时,不使用底层的任何GDI+ Graphics对象的合成,它只是直接GDI调用的枚举。 有关更多信息,请参见此问题,但所有答案都说了同样的事情。
如果您可以将文件转换为EMF Plus,则会使用GDI+方法来呈现内容,并使用GDI+合成,包括抗锯齿。如果您已经在使用WPF,则还可以考虑导出为WPF可以呈现抗锯齿的XPS。
如果无法在源处进行转换,则可以从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 });
emfPlus.Save(@"drawing.emf");
}
}
这里有一个LinqPad的工作示例。它将WMF文件(drawing.wmf)转换为EMF Plus元文件,并在结果面板中显示它。
Paint中的WMF文件:
![没有抗锯齿的WMF文件](https://istack.dev59.com/YvJyw.webp)
Paint中转换后的EMF+文件:
![带有抗锯齿的EMF+文件](https://istack.dev59.com/mBOFF.webp)
为了完整起见,上述GdipConvertToEmfPlus
方法是GDI+的所谓 "flat API" 的一部分。它最初的目的只是为了服务于 GDI+ C++ 类。使用此方法的C++ API 被称为Metafile.ConvertToEmfPlus
。
Graphics
来自于System.Drawing
,Metafile
来自于System.Drawing.Image
,两个命名空间都属于WinForms。 - Clemens