You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WPF实现网页转PDF(使用Microsoft Print to PDF打印机)

解决WPF .NET6中HTML转PDF的几种方案

方案1:利用WPF WebBrowser的COM底层接口实现打印

WPF的WebBrowser控件本身没有公开Print()方法,但它封装了IE的COM组件,我们可以通过获取IWebBrowser2接口来调用打印功能:

  1. 先定义所需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
}
  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,无需依赖系统打印机设置:

  1. 安装NuGet包:CefSharp.Wpf.NETCore(适配.NET6版本)

  2. 在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);
}
  1. 实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:13:12