C# WPF实现网页转PDF(使用Microsoft Print to PDF打印机)
解决WPF .NET6中HTML转PDF的几种方案
方案1:利用WPF WebBrowser的COM底层接口实现打印
WPF的WebBrowser控件本身没有公开Print()方法,但它封装了IE的COM组件,我们可以通过获取IWebBrowser2接口来调用打印功能:
- 先定义所需COM接口(需添加
using System.Runtime.InteropServices;):
[ComImport, Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IWebBrowser2 { [DispId(61529)] void Print(); [DispId(61531)] void ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, ref object pvaIn, ref object pvaOut); } public enum OLECMDID { OLECMDID_PRINT = 6, OLECMDEXECOPT_DONTPROMPTUSER = 2 } public enum OLECMDEXECOPT { OLECMDEXECOPT_DONTPROMPTUSER = 2, OLECMDEXECOPT_PROMPTUSER = 1 }
- 在WebBrowser加载完成后触发打印:
private async void ConvertHtmlToPdf(string htmlFilePath, string pdfOutputPath) { // 加载本地HTML文件 webBrowser.Source = new Uri(htmlFilePath); // 等待页面完全加载渲染 await WaitForBrowserReady(webBrowser); // 获取底层COM接口实例 var browserCom = (IWebBrowser2)webBrowser.GetType().InvokeMember( "ActiveXInstance", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, webBrowser, null); // 设置默认打印机为Microsoft Print to PDF SetDefaultPrinter("Microsoft Print to PDF"); // 静默打印(不弹出对话框) object emptyIn = null; object emptyOut = null; browserCom.ExecWB(OLECMDID.OLECMDID_PRINT, OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, ref emptyIn, ref emptyOut); // 等待打印完成后,将默认输出的PDF(文档文件夹下的Document.pdf)移动到指定路径 await Task.Delay(2000); var defaultPdf = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Document.pdf"); if (File.Exists(defaultPdf)) { if (File.Exists(pdfOutputPath)) File.Delete(pdfOutputPath); File.Move(defaultPdf, pdfOutputPath); } } private async Task WaitForBrowserReady(WebBrowser browser) { while (!browser.IsLoaded || browser.Document == null || browser.Document.Body == null) { await Task.Delay(100); } await Task.Delay(500); // 额外等待渲染完成 } [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool SetDefaultPrinter(string printerName);
方案2:使用CefSharp.Wpf(推荐,基于Chrome内核)
如果不想依赖IE的旧内核,CefSharp是更优选择,它支持直接将渲染后的HTML导出为PDF,无需依赖系统打印机设置:
安装NuGet包:
CefSharp.Wpf.NETCore(适配.NET6版本)在App.xaml.cs中初始化CefSharp:
protected override void OnStartup(StartupEventArgs e) { Cef.Initialize(new CefSettings()); base.OnStartup(e); } protected override void OnExit(ExitEventArgs e) { Cef.Shutdown(); base.OnExit(e); }
- 实现HTML转PDF逻辑:
private async Task ConvertHtmlToPdfWithCef(string htmlFilePath, string pdfOutputPath) { var chromiumBrowser = new ChromiumWebBrowser(); chromiumBrowser.Load(htmlFilePath); // 等待页面加载渲染完成 await WaitForCefReady(chromiumBrowser); // 配置PDF打印参数 var printSettings = new PdfPrintSettings { MarginType = CefPdfPrintMarginType.Default, PaperSize = CefPdfPrintPaperSize.Default, OutputFilePath = pdfOutputPath }; // 静默导出PDF var success = await chromiumBrowser.PrintToPdfAsync(printSettings); if (!success) { throw new Exception("PDF导出失败"); } } private async Task WaitForCefReady(ChromiumWebBrowser browser) { while (!browser.IsBrowserInitialized || browser.Loading) { await Task.Delay(100); } await Task.Delay(500); }
方案3:调用Edge浏览器静默打印
如果不需要嵌入控件,可以直接调用系统Edge浏览器完成后台打印,适合批量处理场景:
private void ConvertHtmlToPdfWithEdge(string htmlFilePath, string pdfOutputPath) { // 定位Edge浏览器路径 var edgePath = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"; if (!File.Exists(edgePath)) { edgePath = @"C:\Program Files\Microsoft\Edge\Application\msedge.exe"; } // 构建命令行参数:无头模式打印HTML到指定PDF var url = $"file:///{htmlFilePath.Replace("\\", "/")}"; var arguments = $"--headless --disable-gpu --print-to-pdf=\"{pdfOutputPath}\" \"{url}\""; var processInfo = new ProcessStartInfo(edgePath, arguments) { CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true }; using var process = Process.Start(processInfo); process.WaitForExit(); if (process.ExitCode != 0) { var errorMsg = process.StandardError.ReadToEnd(); throw new Exception($"Edge打印失败:{errorMsg}"); } }
各方案对比
- 方案1:依赖IE内核,渲染效果可能滞后于现代浏览器,需要处理打印机设置和文件移动,适合旧项目兼容。
- 方案2:渲染效果接近Chrome,API友好,支持自定义打印参数,推荐用于新项目。
- 方案3:无需嵌入控件,适合后台批量处理,依赖系统已安装Edge浏览器。
内容的提问来源于stack exchange,提问作者Colin Slater
相关产品推荐
相关产品推荐

