如何使用Microsoft Print To PDF将EMF矢量图打印为PDF?
解决方案:直接绘制EMF矢量图到PrintDocument以生成矢量PDF
刚好之前做过类似的需求,我来给你说下正确的实现方式——你现在的问题出在把EMF转成Bitmap绘制,这就丢失了矢量信息,要直接在打印上下文的Graphics里绘制EMF文件,这样输出的PDF才会保持矢量属性,放大也不会模糊。
核心思路
不要将EMF转换为Bitmap,而是使用Metafile类直接加载EMF文件,然后在PrintPage事件的打印上下文Graphics对象上调用DrawImage方法。这样整个绘制过程会保留矢量数据,最终通过Microsoft Print To PDF生成的PDF文件里的内容也是矢量格式。
完整代码示例
下面是可直接复用的实现代码,包含EMF加载、打印配置和矢量绘制逻辑:
using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Windows.Forms; public class EmfVectorPdfPrinter { private Metafile _targetEmf; public void PrintEmfToPdf(string emfFilePath) { // 加载EMF文件,注意使用using确保流资源释放 using (var emfStream = new FileStream(emfFilePath, FileMode.Open, FileAccess.Read)) { _targetEmf = new Metafile(emfStream); } var printDoc = new PrintDocument(); // 配置Microsoft Print To PDF打印机 printDoc.PrinterSettings.PrinterName = "Microsoft Print To PDF"; printDoc.PrinterSettings.PrintToFile = true; // 可选:直接指定输出路径,不设置的话系统会弹出保存对话框 printDoc.PrinterSettings.PrintFileName = @"D:\Output\VectorEmfOutput.pdf"; // 绑定打印页事件 printDoc.PrintPage += OnPrintPage; // 执行打印 printDoc.Print(); // 打印完成后释放EMF资源 _targetEmf.Dispose(); } private void OnPrintPage(object sender, PrintPageEventArgs e) { // 获取打印页面的可用区域 var printBounds = e.PageBounds; // 获取EMF文件的原始尺寸 var emfSize = new SizeF(_targetEmf.Width, _targetEmf.Height); // 计算缩放比例,保持宽高比且适配打印区域 float scaleX = printBounds.Width / emfSize.Width; float scaleY = printBounds.Height / emfSize.Height; float finalScale = Math.Min(scaleX, scaleY); // 计算居中绘制的坐标 float drawX = (printBounds.Width - emfSize.Width * finalScale) / 2; float drawY = (printBounds.Height - emfSize.Height * finalScale) / 2; // 直接在打印上下文绘制EMF,保留矢量信息 e.Graphics.DrawImage(_targetEmf, drawX, drawY, emfSize.Width * finalScale, emfSize.Height * finalScale); // 标记没有更多打印页 e.HasMorePages = false; } }
关键细节说明
- 矢量保留的核心:直接使用
Metafile加载EMF并在打印Graphics上绘制,而非先转成Bitmap。Bitmap是栅格图像,会丢失矢量数据,而Metafile会保留原始的矢量指令。 - 缩放逻辑:通过计算最小缩放比例保证EMF完整适配打印页,同时保持宽高比避免变形,还可以根据需求调整为拉伸或固定尺寸。
- 打印机配置:如果不需要预先指定PDF路径,删除
PrintFileName的设置即可,系统会自动弹出保存对话框让用户选择路径。
注意事项
- 确保项目引用了
System.Drawing和System.Windows.Forms程序集(WinForms项目默认已包含,控制台项目需手动添加引用)。 - 要正确释放
Metafile和文件流资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者L. Guthardt




