跳至页脚内容
PDF 工具

发现 2025 年最佳 PDF 涂黑软件

选择一个用于在2026年将HTML转换为PDF的C#库,其核心决策在于选择哪种渲染引擎适合您实际制作的文档。 在.NET 10上,此领域分为三组。 基于浏览器的引擎(通过PuppeteerSharp、Playwright或嵌入式构建的Chromium)能准确渲染现代CSS和JavaScript。 程序化库(iText、PdfSharp)通过自定义解析器绘制PDF,牺牲现代网页保真度以追求小巧的体积。 代码优先的布局工具(QuestPDF)完全跳过HTML。 本比较涵盖每个选项并提供了工作C#代码、评估标准、原始基准测试和许可条款,以决定您可以发布的内容。

简短总结: 快速的答案和最快的工作代码

为了精确渲染当前的CSS和JavaScript,使用浏览器级引擎。免费的途径是PuppeteerSharp或Playwright,它们提供了Chrome级输出,但需要您管理独立的浏览器进程和大型二进制文件。 商业途径则在包内嵌入Chromium,无需单独安装或启动。 对于简单的静态文档,PdfSharp之类的轻量级库就足够了。 对于没有HTML源代码的代码定义布局,QuestPDF是最短路径。

使用嵌入引擎最快的PDF生成路径是一个简单的渲染调用:

using IronPdf;

// The embedded Chromium engine ships inside the package, so no browser is launched or downloaded
var renderer = new ChromePdfRenderer();
// One synchronous call parses the HTML string and produces an in-memory PDF document
var pdf = renderer.RenderHtmlAsPdf("<h1>Invoice</h1><p>Generated from HTML.</p>");
// Write the rendered document to disk
pdf.SaveAs("output.pdf");
using IronPdf;

// The embedded Chromium engine ships inside the package, so no browser is launched or downloaded
var renderer = new ChromePdfRenderer();
// One synchronous call parses the HTML string and produces an in-memory PDF document
var pdf = renderer.RenderHtmlAsPdf("<h1>Invoice</h1><p>Generated from HTML.</p>");
// Write the rendered document to disk
pdf.SaveAs("output.pdf");
Imports IronPdf

' The embedded Chromium engine ships inside the package, so no browser is launched or downloaded
Dim renderer As New ChromePdfRenderer()
' One synchronous call parses the HTML string and produces an in-memory PDF document
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Invoice</h1><p>Generated from HTML.</p>")
' Write the rendered document to disk
pdf.SaveAs("output.pdf")
$vbLabelText   $csharpLabel

完整的比较、基准测试和许可详情如下。

按场景快速推荐表

在深入阅读之前,先根据您的限制选择一个选项。

如果您需要 推荐选择 为什么
现代CSS,Flexbox,Grid,大规模的网络字体 IronPDF(嵌入式Chromium) 精确的渲染,快速的热启动渲染,无需部署外部浏览器
免费的浏览器级渲染,愿意管理操作 PuppeteerSharp或Playwright 真正的Chromium,MIT许可证,部署重量较重
简单的静态HTML,没有JavaScript 使用HtmlRenderer的PdfSharp 轻量级,免费,限于旧CSS
程序化固定布局,无HTML来源 QuestPDF 流畅的C#API,非常快,不是一个HTML渲染器
零基础设施,托管处理 一个HTML-to-PDF API 没有需要在应用程序中维护的渲染引擎
依赖于wkhtmltopdf的旧项目 迁移到一个Chromium引擎 wkhtmltopdf已归档,在当前CSS上失败,并且携带一个严重的SSRF CVE

C&#35中将HTML转换为PDF的困难之处

浏览器为屏幕渲染流体内容; PDF要求固定页面、精确的尺寸和严格的分页。 这些模型之间的差距决定了库的成败。 五个标准将它们分开,这些标准适用于每个工具,不论其供应商。

  1. 渲染引擎和现代CSS:解析HTML和CSS的引擎是核心的差异点。 当前模板依赖于CSS Flexbox用于对齐,CSS Grid用于二维布局,@font-face用于排版,SVG用于矢量资产。 基于旧的WebKit分支或自定义解析器的引擎往往在这些方面默默失败,将样式化的布局折叠到一个垂直堆栈中。 当将屏幕布局转变为纸质版时,正确处理@media print规则同样重要。

  2. JavaScript执行和渲染等待:如今的大部分内容都是在客户端构建的。图表库如Chart.js和单页框架如Blazor WebAssembly在页面完成前用JavaScript构建DOM。 没有JavaScript引擎的库会产生空白图表或半加载的页面,这使得执行业务脚本和等待渲染就绪信号对动态文档来说至关重要。

  3. 部署重量和冷启动:驱动外部无头浏览器的工具会下载数百兆字节的二进制文件,增加容器镜像体积并减缓冷启动。 在存储和内存紧张的无服务器环境中,如AWS Lambda或Azure Functions,容器重量可能决定库是否可行。

  4. 许可证及其法律范围:许可证不仅决定成本。 .NET PDF 领域涵盖了宽松条款(MIT、Apache 2.0)、可能要求披露面向网络应用源代码的copyleft条款(AGPLv3)、收入门槛的社区层和永久的商业许可证。 错误的选择可能会在审计时露出义务。

  5. 大规模性能和内存:在控制台测试中没问题的库在并发Web API下可能会卡住。 一些库将工作流式传输; 其他库会将整个文档一次性加载到内存中,并在批量作业期间触发垃圾收集暂停。 冷启动、热渲染和每次渲染的内存是需要关注的三个不同指标。

每个库附带工作代码

先介绍免费的开源选项。以下每段代码都在.NET 10上编译和运行,Chromium引擎显示了HTML字符串和URL输入,因为它们支持两者。

PuppeteerSharp

PuppeteerSharp是Google的Node.js Puppeteer的.NET移植版,首次发布于2017年。它通过Chrome DevTools协议驱动一个无头Chromium实例。 它是一个进程协调器,而非进程内库:应用程序通过BrowserFetcher下载一个Chromium构建,启动浏览器,设置页面内容,并捕捉PDF。

using PuppeteerSharp;
using System.Threading.Tasks;

public class PuppeteerExample
{
    public async Task GeneratePdfAsync()
    {
        // Download a matching Chromium build if it is not already present (the 100-300 MB fetch)
        await new BrowserFetcher().DownloadAsync();

        // Start a headless browser process; await using disposes it to avoid orphaned processes
        await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
        // Open a fresh tab to work in
        await using var page = await browser.NewPageAsync();

        // Load the HTML directly into the page instead of navigating to a URL
        await page.SetContentAsync("<h1>Invoice Report</h1><p>Rendered with PuppeteerSharp.</p>");
        // Drive Chrome's print pipeline to emit the PDF file
        await page.PdfAsync("puppeteer_output.pdf");
    }
}
using PuppeteerSharp;
using System.Threading.Tasks;

public class PuppeteerExample
{
    public async Task GeneratePdfAsync()
    {
        // Download a matching Chromium build if it is not already present (the 100-300 MB fetch)
        await new BrowserFetcher().DownloadAsync();

        // Start a headless browser process; await using disposes it to avoid orphaned processes
        await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
        // Open a fresh tab to work in
        await using var page = await browser.NewPageAsync();

        // Load the HTML directly into the page instead of navigating to a URL
        await page.SetContentAsync("<h1>Invoice Report</h1><p>Rendered with PuppeteerSharp.</p>");
        // Drive Chrome's print pipeline to emit the PDF file
        await page.PdfAsync("puppeteer_output.pdf");
    }
}
Imports PuppeteerSharp
Imports System.Threading.Tasks

Public Class PuppeteerExample
    Public Async Function GeneratePdfAsync() As Task
        ' Download a matching Chromium build if it is not already present (the 100-300 MB fetch)
        Await New BrowserFetcher().DownloadAsync()

        ' Start a headless browser process; using disposes it to avoid orphaned processes
        Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {.Headless = True})
            ' Open a fresh tab to work in
            Using page = Await browser.NewPageAsync()
                ' Load the HTML directly into the page instead of navigating to a URL
                Await page.SetContentAsync("<h1>Invoice Report</h1><p>Rendered with PuppeteerSharp.</p>")
                ' Drive Chrome's print pipeline to emit the PDF file
                Await page.PdfAsync("puppeteer_output.pdf")
            End Using
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

要抓取一个实时URL而不是字符串,请在调用前导航到它:

// Navigate the tab to a live URL so the loaded page becomes the render source
await page.GoToAsync("https://example.com");
// Capture whatever is currently displayed as a PDF
await page.PdfAsync("from_url.pdf");
// Navigate the tab to a live URL so the loaded page becomes the render source
await page.GoToAsync("https://example.com");
// Capture whatever is currently displayed as a PDF
await page.PdfAsync("from_url.pdf");
Imports System.Threading.Tasks

' Navigate the tab to a live URL so the loaded page becomes the render source
Await page.GoToAsync("https://example.com")
' Capture whatever is currently displayed as a PDF
Await page.PdfAsync("from_url.pdf")
$vbLabelText   $csharpLabel

优势:

  • 渲染与Google Chrome匹配,支持完整的Flexbox、Grid和网络字体。
  • 执行JavaScript并可在捕获前等待网络闲置。
  • MIT许可,因此商业使用不带有copyleft义务。

限制:

  • 首次运行下载100 MB至300 MB的Chromium构建。
  • 每个浏览器实例消耗大量内存,因此并发批量处理需要一个浏览器池。
  • 没有内建的PDF/A或PDF/UA输出。

许可证:MIT。 当您需要免费Chrome保真度输出且团队能吸收运维开销时选择它。 有关此权衡的重点对比,请参见PuppeteerSharp与IronPDF比较

编剧for .NET

Playwright由微软维护,是一个跨浏览器自动化框架,支持Chromium、WebKit和Firefox。 团队常使用Page.PdfAsync将其重用于HTML到PDF转换,但PDF生成仅与Chromium兼容。 安装时通过一次性安装步骤获取浏览器二进制文件。

using Microsoft.Playwright;
using System.Threading.Tasks;

public class PlaywrightExample
{
    public async Task GeneratePdfAsync()
    {
        // Create the编剧driver that manages the installed browser binaries
        using var playwright = await Playwright.CreateAsync();
        // PDF output is Chromium-only, so launch the Chromium build specifically
        await using var browser = await playwright.Chromium.LaunchAsync();
        // Open a new page (tab) to render into
        var page = await browser.NewPageAsync();

        // Set the HTML content in place rather than navigating to a URL
        await page.SetContentAsync("<html><body><h1>Sales Dashboard</h1></body></html>");
        // Emit the PDF with an explicit A4 page format
        await page.PdfAsync(new PagePdfOptions { Path = "playwright_output.pdf", Format = "A4" });
    }
}
using Microsoft.Playwright;
using System.Threading.Tasks;

public class PlaywrightExample
{
    public async Task GeneratePdfAsync()
    {
        // Create the编剧driver that manages the installed browser binaries
        using var playwright = await Playwright.CreateAsync();
        // PDF output is Chromium-only, so launch the Chromium build specifically
        await using var browser = await playwright.Chromium.LaunchAsync();
        // Open a new page (tab) to render into
        var page = await browser.NewPageAsync();

        // Set the HTML content in place rather than navigating to a URL
        await page.SetContentAsync("<html><body><h1>Sales Dashboard</h1></body></html>");
        // Emit the PDF with an explicit A4 page format
        await page.PdfAsync(new PagePdfOptions { Path = "playwright_output.pdf", Format = "A4" });
    }
}
Imports Microsoft.Playwright
Imports System.Threading.Tasks

Public Class PlaywrightExample
    Public Async Function GeneratePdfAsync() As Task
        ' Create the Playwright driver that manages the installed browser binaries
        Using playwright = Await Playwright.CreateAsync()
            ' PDF output is Chromium-only, so launch the Chromium build specifically
            Await Using browser = Await playwright.Chromium.LaunchAsync()
                ' Open a new page (tab) to render into
                Dim page = Await browser.NewPageAsync()

                ' Set the HTML content in place rather than navigating to a URL
                Await page.SetContentAsync("<html><body><h1>Sales Dashboard</h1></body></html>")
                ' Emit the PDF with an explicit A4 page format
                Await page.PdfAsync(New PagePdfOptions With {.Path = "playwright_output.pdf", .Format = "A4"})
            End Using
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

在首次运行之前,通过pwsh bin/Debug/net10.0/playwright.ps1 install chromium安装浏览器(或在代码中调用等效安装入口)。

对于实时URL,先导航到页面:

// Load a live URL so its rendered DOM becomes the PDF source
await page.GotoAsync("https://example.com");
// Export the loaded page as an A4 PDF
await page.PdfAsync(new PagePdfOptions { Path = "from_url.pdf", Format = "A4" });
// Load a live URL so its rendered DOM becomes the PDF source
await page.GotoAsync("https://example.com");
// Export the loaded page as an A4 PDF
await page.PdfAsync(new PagePdfOptions { Path = "from_url.pdf", Format = "A4" });
Imports System.Threading.Tasks

' Load a live URL so its rendered DOM becomes the PDF source
Await page.GotoAsync("https://example.com")
' Export the loaded page as an A4 PDF
Await page.PdfAsync(New PagePdfOptions With {.Path = "from_url.pdf", .Format = "A4"})
$vbLabelText   $csharpLabel

亮点:

  • 由微软支持,具有主动的发布周期。
  • 一旦浏览器启动,首次渲染延迟低。
  • 准确渲染现代网络标准和客户端JavaScript。

需注意:

  • 与PuppeteerSharp同样的重型二进制文件和浏览器管理。
  • 不小心处理浏览器上下文会导致内存攀升。
  • PDF输出是Chrome打印管道的附带功能,因此缺乏文档操作功能。

许可证:MIT。 在项目已经使用Playwright进行测试并想复用它进行免费渲染时理想。

wkhtmltopdf(通过DinkToPdf)

wkhtmltopdf十多年来一直是默认的HTML到PDF工具。 在.NET中,通常通过DinkToPdf进行消费,它是对本机libwkhtmltox库的C#包装器。 包装API是干净的,但引擎底层是问题所在。

using DinkToPdf;

public class DinkToPdfExample
{
    public void GeneratePdf()
    {
        // SynchronizedConverter serializes calls into the non-thread-safe native libwkhtmltox library
        var converter = new SynchronizedConverter(new PdfTools());

        // Describe the document: global page settings plus one or more HTML content objects
        var doc = new HtmlToPdfDocument
        {
            // Set the paper size and the output file path for the whole document
            GlobalSettings = { PaperSize = PaperKind.A4, Out = "legacy_output.pdf" },
            // Each object is a chunk of HTML to render into the PDF
            Objects = { new ObjectSettings { HtmlContent = "<h1>Legacy Report</h1>" } }
        };

        // Hand the descriptor to the native engine, which writes the file defined in Out
        converter.Convert(doc);
    }
}
using DinkToPdf;

public class DinkToPdfExample
{
    public void GeneratePdf()
    {
        // SynchronizedConverter serializes calls into the non-thread-safe native libwkhtmltox library
        var converter = new SynchronizedConverter(new PdfTools());

        // Describe the document: global page settings plus one or more HTML content objects
        var doc = new HtmlToPdfDocument
        {
            // Set the paper size and the output file path for the whole document
            GlobalSettings = { PaperSize = PaperKind.A4, Out = "legacy_output.pdf" },
            // Each object is a chunk of HTML to render into the PDF
            Objects = { new ObjectSettings { HtmlContent = "<h1>Legacy Report</h1>" } }
        };

        // Hand the descriptor to the native engine, which writes the file defined in Out
        converter.Convert(doc);
    }
}
Imports DinkToPdf

Public Class DinkToPdfExample
    Public Sub GeneratePdf()
        ' SynchronizedConverter serializes calls into the non-thread-safe native libwkhtmltox library
        Dim converter = New SynchronizedConverter(New PdfTools())

        ' Describe the document: global page settings plus one or more HTML content objects
        Dim doc = New HtmlToPdfDocument With {
            ' Set the paper size and the output file path for the whole document
            .GlobalSettings = New GlobalSettings With {.PaperSize = PaperKind.A4, .Out = "legacy_output.pdf"},
            ' Each object is a chunk of HTML to render into the PDF
            .Objects = {New ObjectSettings With {.HtmlContent = "<h1>Legacy Report</h1>"}}
        }

        ' Hand the descriptor to the native engine, which writes the file defined in Out
        converter.Convert(doc)
    End Sub
End Class
$vbLabelText   $csharpLabel

这段代码可以编译,但在干净的机器上运行它会抛出System.DllNotFoundException: Unable to load DLL 'libwkhtmltox',直到本机二进制文件被复制到输出目录。 那个本机依赖步骤是这个引擎带来的部署摩擦的第一征兆。

优点:

  • 冷启动快速,没有现代浏览器需要初始化。
  • 内存消耗低,每次渲染大约50 MB。

缺点:

  • 它附带的QtWebKit引擎(大约为2012-2013年的WebKit快照,Qt本身在2015年弃用并在2016年移除)不能渲染Flexbox、Grid或现代JavaScript。
  • wkhtmltopdf仓库于2023年1月2日归档,最后的发行版本0.12.6可以追溯到2020年6月。
  • 它携带CVE-2022-35583,这是一个评级为9.8(严重)的服务器端请求伪造漏洞,因为项目不再维护而未被修补。

许可证:DinkToPdf本身是MIT,但它链接了LGPLv3的wkhtmltopdf二进制文件,因此实际义务来自wkhtmltopdf。 适合待迁移的旧工作流,需留意安全风险。 有关完整的迁移图片,请参见wkhtmltopdf vs IronPDF比较

PdfSharp and HtmlRenderer

PdfSharp是一个广泛使用的开源库,但一个常见的误解是它可以自行转换HTML。 但并非如此。 PdfSharp提供了一个低级别、基于坐标的绘图API。 为了转换HTML,您需要将它与社区桥HtmlRenderer.PdfSharp配对,它解析HTML并发出PdfSharp绘图命令。

using PdfSharp;
using TheArtOfDev.HtmlRenderer.PdfSharp;

public class PdfSharpExample
{
    public void GeneratePdf()
    {
        string html = "<h1>Simple Title</h1><p>Statically rendered text.</p>";

        // The HtmlRenderer bridge parses the HTML and emits PdfSharp drawing commands onto an A4 page
        var pdf = PdfGenerator.GeneratePdf(html, PageSize.A4);
        // Persist the resulting PdfSharp document to disk
        pdf.Save("simple_document.pdf");
    }
}
using PdfSharp;
using TheArtOfDev.HtmlRenderer.PdfSharp;

public class PdfSharpExample
{
    public void GeneratePdf()
    {
        string html = "<h1>Simple Title</h1><p>Statically rendered text.</p>";

        // The HtmlRenderer bridge parses the HTML and emits PdfSharp drawing commands onto an A4 page
        var pdf = PdfGenerator.GeneratePdf(html, PageSize.A4);
        // Persist the resulting PdfSharp document to disk
        pdf.Save("simple_document.pdf");
    }
}
Imports PdfSharp
Imports TheArtOfDev.HtmlRenderer.PdfSharp

Public Class PdfSharpExample
    Public Sub GeneratePdf()
        Dim html As String = "<h1>Simple Title</h1><p>Statically rendered text.</p>"

        ' The HtmlRenderer bridge parses the HTML and emits PdfSharp drawing commands onto an A4 page
        Dim pdf = PdfGenerator.GeneratePdf(html, PageSize.A4)
        ' Persist the resulting PdfSharp document to disk
        pdf.Save("simple_document.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

在.NET 10上,两个设置细节很重要。桥接器期望的是Windows-1252代码页,这在现代.NET中默认不存在,因此需要在启动时用Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)注册一次。 将桥接器与新版本的PdfSharp 6.x包配对也会在运行时破坏出一个MissingMethodException,因此让HtmlRenderer拉取其兼容的PdfSharp而不是固定最新版本。

有效之处:

  • 真正宽松的MIT许可证,没有收入限制。
  • 轻量级,没有本机二进制文件或浏览器获取程序。
  • 纯C#,因此在跨操作系统的部署上毫无障碍。

薄弱之处:

  • HTML桥接器仅限于大概是HTML 4.01和CSS Level 2,并且其在九年沉寂之后仅在2025年底看到了一次发布。
  • 完全没有JavaScript执行。
  • page-break-inside: avoid等打印规则不支持,因此表行跨页。

许可证:PdfSharp MIT,HtmlRenderer BSD-3-Clause。 适用于没有复杂布局的简单静态文档。 有关功能逐一对比,请参见PdfSharp vs IronPDF比较

QuestPDF

QuestPDF走了不同的路径:它抛弃了HTML,通过一个流畅的API在C#中定义布局。 对于数据源自对象而非标记的情况,这省去了仅为了解析回来的HTML生成步骤。

using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;

public class QuestPdfExample
{
    public void GeneratePdf()
    {
        // The revenue-gated license tier must be declared before any document is built
        QuestPDF.Settings.License = LicenseType.Community;

        // Compose the layout in C# through the fluent API; no HTML anywhere
        var document = Document.Create(container =>
        {
            container.Page(page =>
            {
                // Define the physical page size and margins
                page.Size(PageSizes.A4);
                page.Margin(2, Unit.Centimetre);
                // Place content into named page regions (header and body)
                page.Header().Text("Programmatic Invoice").FontSize(24);
                page.Content().Text("This document is generated without HTML.");
            });
        });

        // Run the layout engine and write the composed document to a file
        document.GeneratePdf("fluent_layout.pdf");
    }
}
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;

public class QuestPdfExample
{
    public void GeneratePdf()
    {
        // The revenue-gated license tier must be declared before any document is built
        QuestPDF.Settings.License = LicenseType.Community;

        // Compose the layout in C# through the fluent API; no HTML anywhere
        var document = Document.Create(container =>
        {
            container.Page(page =>
            {
                // Define the physical page size and margins
                page.Size(PageSizes.A4);
                page.Margin(2, Unit.Centimetre);
                // Place content into named page regions (header and body)
                page.Header().Text("Programmatic Invoice").FontSize(24);
                page.Content().Text("This document is generated without HTML.");
            });
        });

        // Run the layout engine and write the composed document to a file
        document.GeneratePdf("fluent_layout.pdf");
    }
}
Imports QuestPDF.Fluent
Imports QuestPDF.Helpers
Imports QuestPDF.Infrastructure

Public Class QuestPdfExample
    Public Sub GeneratePdf()
        ' The revenue-gated license tier must be declared before any document is built
        QuestPDF.Settings.License = LicenseType.Community

        ' Compose the layout in VB.NET through the fluent API; no HTML anywhere
        Dim document = Document.Create(Sub(container)
                                           container.Page(Sub(page)
                                                              ' Define the physical page size and margins
                                                              page.Size(PageSizes.A4)
                                                              page.Margin(2, Unit.Centimetre)
                                                              ' Place content into named page regions (header and body)
                                                              page.Header().Text("Programmatic Invoice").FontSize(24)
                                                              page.Content().Text("This document is generated without HTML.")
                                                          End Sub)
                                       End Sub)

        ' Run the layout engine and write the composed document to a file
        document.GeneratePdf("fluent_layout.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

强项:

  • 非常快,因为它跳过了DOM解析和浏览器布局。
  • 可预测的线性内存,适合高吞吐量的批量作业。
  • 一个伴侣应用程序在设计期间提供实时预览和热重载。

弱项:

  • 它是一个布局引擎,而不是HTML渲染器,因此无法转换URL或现有的HTML模板。
  • 现有的HTML或Razor文件需要完全重新编写为流畅的API。
  • 许可证从MIT转移到了收入门槛的模型。

许可证:社区许可证(适用于年收入低于100万美金的企业免费),或付费的Professional和Enterprise层。 适用于由结构化数据驱动的代码定义的固定布局文档。 有关HTML与流畅布局权衡的QuestPDF与IronPDF比较,请参见QuestPDF vs IronPDF比较

iText(pdfHTML)

iText 7和8因程序化PDF操作而得名,而pdfHTML扩展用于HTML转换。 与Chromium工具不同,pdfHTML使用一个自定义解析器,将HTML标记映射到iText对象而不是运行浏览器。

using iText.Html2pdf;
using System.IO;

public class iTextExample
{
    public void GeneratePdf()
    {
        string html = "<h1>Report</h1><p>Converted with pdfHTML.</p>";

        // Open the destination stream; using ensures the file handle is released after writing
        using var dest = File.Create("output.pdf");
        // pdfHTML maps the HTML tags to iText objects and writes them to the stream (no browser involved)
        HtmlConverter.ConvertToPdf(html, dest);
    }
}
using iText.Html2pdf;
using System.IO;

public class iTextExample
{
    public void GeneratePdf()
    {
        string html = "<h1>Report</h1><p>Converted with pdfHTML.</p>";

        // Open the destination stream; using ensures the file handle is released after writing
        using var dest = File.Create("output.pdf");
        // pdfHTML maps the HTML tags to iText objects and writes them to the stream (no browser involved)
        HtmlConverter.ConvertToPdf(html, dest);
    }
}
Imports iText.Html2pdf
Imports System.IO

Public Class iTextExample
    Public Sub GeneratePdf()
        Dim html As String = "<h1>Report</h1><p>Converted with pdfHTML.</p>"

        ' Open the destination stream; using ensures the file handle is released after writing
        Using dest As FileStream = File.Create("output.pdf")
            ' pdfHTML maps the HTML tags to iText objects and writes them to the stream (no browser involved)
            HtmlConverter.ConvertToPdf(html, dest)
        End Using
    End Sub
End Class
$vbLabelText   $csharpLabel

在新项目上,这会抛出,直到您添加itext7.bouncy-castle-adapter包,这是iText在其加密路径中需要的。 那个额外的依赖很容易被忽略,且没有它会产生一个不透明的错误。

优势:

  • 深度PDF操作、签名和被动iText生态系统中的删除。
  • 从语义HTML生成PDF/A和PDF/UA,适合合规工作。
  • 启动快,因为不需要启动浏览器。

缺点:

  • 没有脚本执行,因此动态内容不会渲染。
  • CSS3功能如Grid不支持并默默失败。
  • AGPLv3许可要求对于封闭源应用需要商业许可,大文件被完整缓冲而非流式传输。

许可证:AGPLv3或商业。 选择它用于重度PDF操作和受控、静态HTML的合规工作流程。 有关许可和操作详情,请参见iText 7 vs IronPDF比较

IronPDF

IronPDF在其NuGet包中嵌入一个Chromium引擎并通过C# API进行暴露,因此无需外部启动或池化。 它位于免费浏览器工具和程序化库之间,以许可证成本换取渲染保真度,无需管理浏览器。

using IronPdf;
using System.Threading.Tasks;

public class IronPdfExample
{
    public async Task GeneratePdfAsync()
    {
        // Create the in-process Chromium renderer (no external browser to launch)
        var renderer = new ChromePdfRenderer();
        // Turn on theJavaScriptengine so client-side chart scripts execute before capture
        renderer.RenderingOptions.EnableJavaScript = true;
        // Wait 500 ms after load to let JavaScript-built content settle before rendering
        renderer.RenderingOptions.WaitFor.RenderDelay(500);

        // Render the HTML string asynchronously into an in-memory PDF
        var pdf = await renderer.RenderHtmlAsPdfAsync("<h1>Quarterly Report</h1><div class='chart'></div>");
        // Save the finished PDF to disk
        pdf.SaveAs("report.pdf");
    }
}
using IronPdf;
using System.Threading.Tasks;

public class IronPdfExample
{
    public async Task GeneratePdfAsync()
    {
        // Create the in-process Chromium renderer (no external browser to launch)
        var renderer = new ChromePdfRenderer();
        // Turn on theJavaScriptengine so client-side chart scripts execute before capture
        renderer.RenderingOptions.EnableJavaScript = true;
        // Wait 500 ms after load to let JavaScript-built content settle before rendering
        renderer.RenderingOptions.WaitFor.RenderDelay(500);

        // Render the HTML string asynchronously into an in-memory PDF
        var pdf = await renderer.RenderHtmlAsPdfAsync("<h1>Quarterly Report</h1><div class='chart'></div>");
        // Save the finished PDF to disk
        pdf.SaveAs("report.pdf");
    }
}
Imports IronPdf
Imports System.Threading.Tasks

Public Class IronPdfExample
    Public Async Function GeneratePdfAsync() As Task
        ' Create the in-process Chromium renderer (no external browser to launch)
        Dim renderer As New ChromePdfRenderer()
        ' Turn on the JavaScript engine so client-side chart scripts execute before capture
        renderer.RenderingOptions.EnableJavaScript = True
        ' Wait 500 ms after load to let JavaScript-built content settle before rendering
        renderer.RenderingOptions.WaitFor.RenderDelay(500)

        ' Render the HTML string asynchronously into an in-memory PDF
        Dim pdf = Await renderer.RenderHtmlAsPdfAsync("<h1>Quarterly Report</h1><div class='chart'></div>")
        ' Save the finished PDF to disk
        pdf.SaveAs("report.pdf")
    End Function
End Class
$vbLabelText   $csharpLabel

相同的渲染器通过一次调用将URL转换为PDF

// RenderUrlAsPdf fetches and renders the live page in one call, no navigation step needed
var fromUrl = new ChromePdfRenderer().RenderUrlAsPdf("https://example.com");
// Write the captured page to disk
fromUrl.SaveAs("from_url.pdf");
// RenderUrlAsPdf fetches and renders the live page in one call, no navigation step needed
var fromUrl = new ChromePdfRenderer().RenderUrlAsPdf("https://example.com");
// Write the captured page to disk
fromUrl.SaveAs("from_url.pdf");
' RenderUrlAsPdf fetches and renders the live page in one call, no navigation step needed
Dim fromUrl = (New ChromePdfRenderer()).RenderUrlAsPdf("https://example.com")
' Write the captured page to disk
fromUrl.SaveAs("from_url.pdf")
$vbLabelText   $csharpLabel

它还将Razor和MVC视图渲染为PDF,直接转换HTML文件。 完整功能演练在HTML到PDF教程中。

优点:

  • 浏览器级渲染,可处理Grid、Flexbox和客户端脚本。
  • 无需外部可执行文件或浏览器池化的部署。
  • 生成PDF/A并应用数字签名,将其与测试框架分开。

缺点:

  • 需要商业许可证,没有免费的生产层。
  • 从新的部署开始,首次渲染带有一次性的初始化成本,之后的渲染进入快速的热路径。

许可证:商业,永久。 当需要以量处理当前CSS,优先减少操作开销同时保持高保真度时选择它。

完整比较表

每个库一行,并包含许可证列,因为它直接驱动了免费与付费的决策。

引擎 JavaScript 现代 CSS 部署重量 许可证 最适合
IronPDF 嵌入式 Chromium 满的 轻量(NuGet) 商业翻译 现代CSS大规模
PuppeteerSharp 外部Chromium 满的 重量级(二进制下载) 麻省理工学院 免费的浏览器渲染
编剧 外部Chromium 满的 重量级(二进制下载) 麻省理工学院 现代免费的渲染
wkhtmltopdf 旧的QtWebKit 有限的 中等(本机库) LGPLv3(包装MIT) 旧工作流
PdfSharp + HtmlRenderer 自定义绘图 有限的 轻量 麻省理工学院/ BSD-3 简单的静态HTML
QuestPDF 编程 不适用 不适用 轻量 社区 / 付费 代码定义的布局
iText pdfHTML 自定义解析器 有限的 语言 AGPLv3 / 商业 PDF 操作

集成前核实每个单元格与每个库的当前版本,因为许可证和引擎支持可能会变。

免费对付费:何时该做怎样的选择

在.NET PDF领域,所谓的"免费"工具可能隐藏了运营和法律成本,因此标记何时免费工具是正确选择,是诚实的起点。

对于简单的静态文档、低体积或拥有管理外部进程运营能力的团队来说,免费开源库确实足够。 不带复杂样式的文本丰富收据通过MIT许可的PdfSharp渲染效果良好。对于已经使用Playwright进行测试并解决了容器化的团队,偶尔的PDF任务再利用它效率很高。

免费软件不意味着免费实施。 开源无头浏览器的隐藏成本体现在维护时间上:池化浏览器生命周期以防止服务器在负载下崩溃,配置Linux共享库依赖项以跨容器镜像,以及吸收重型浏览器进程的基础设施成本。 对于琐碎的静态文档,付费的浏览器引擎显得大材小用,轻量级的免费库是更好的选择。

当工作需要准确的CSS3大规模处理、可访问的PDF/UA输出和超越采购成本的部署简单性时,商业Chromium库就变得合理了。商业许可还消除了copyleft暴露。 向SaaS平台添加诸如iText的AGPLv3库可能会迫使公司在没有购买商业许可证的情况下发布其源代码。 真正的比较是所有权的总成本:运营时间和法律风险在一边,许可证费用在另一边。

基准测试

下面的每个数字都来自一台机器上的亲自运行,因此请将它们视为方向性的。 测试文档是一个使用CSS Grid的30行发票,头部有一个内联的JavaScript条形图。 测试在一个标准Windows工作站上,在.NET 10上运行。每个热渲染数字是8次渲染后的平均值,峰值内存是.NET进程及其产生的任何浏览器子进程的峰值工作集。

冷启动(每个进程) 热渲染(8次的平均值) 峰值内存
IronPDF 345 ms 202 ms 406 MB
PuppeteerSharp 746 ms 204 ms 611 MB
编剧 588 ms 132 ms 515 MB
wkhtmltopdf, iText, PdfSharp sub-second not comparable 50到120 MB

一旦热起来,三个浏览器引擎将在大约130到200 ms之间渲染相同的文档,在这次运行中Playwright最快,而IronPDF和PuppeteerSharp紧随其后。 冷启动时,嵌入引擎在这里最快,因为它在进程中运行,没有单独的浏览器需要启动,尽管全新部署后的第一次渲染会吸收一次引擎初始化成本,后续进程启动则跳过。旧的和自定义解析器工具(wkhtmltopdf、iText、PdfSharp)在一秒以内启动,并使用最少的内存,但这个优势在测试文档中无效,因为它们无法正确渲染其Grid布局或JavaScript图表。 在没有先提供其本机二进制文件的情况下,wkhtmltopdf根本无法运行。

保真度差距在输出中显现。 浏览器引擎渲染CSS Grid头部、已设计的表格和JavaScript条形图:

测试发票由Chromium引擎渲染,CSS Grid头部、已设计的表格和JavaScript条形图均在效果。

通过PdfSharp与HtmlRenderer渲染的相同文档丢失了Grid头部、表头样式和JavaScript图表:

相同发票由PdfSharp与HtmlRenderer渲染,缺失CSS Grid头部和JavaScript图表。

应该使用哪一个?

每个常见场景的简短裁定:

  • CSS框架和单页输出:只有浏览器级渲染器能跟上。
  • 简单的静态HTML或文本收据:PdfSharp和一个小的免费堆栈覆盖。
  • 没有标记的程序化、数据驱动的布局:QuestPDF最快。
  • 有操作能力的免费浏览器渲染:PuppeteerSharp或Playwright。
  • 零基础设施:一个托管的HTML-to-PDF API。
  • 迁移wkhtmltopdf的旧项目:迁移到一个嵌入式引擎以获得安全与CSS支持。

当重载CSS框架输出与低运维需求相遇时,IronPDF是首先值得尝试的嵌入选项,而免费浏览器工具仍是可以拥有无头浏览器周围操作的团队的正确选择。

部署注意事项

.NET文档生成中最大的摩擦是一个在Windows笔记本上工作的库在Linux容器中失败的间隙。 选择一个库意味着预见它将在何处发布。

在Docker中,像PuppeteerSharp和Playwright这样的有序浏览器需要一个基础映像,带有Chromium的Linux依赖,包括libgbm1。 微软发布Playwright .NET映像v1.NN.0-noble标签)来涵盖这些,这些映像运行接近一GB。 嵌入引擎通过按架构NuGet包绕过膨胀,例如apt-get步骤。

AWS Lambda抬起了另一个高墙。 它在未解压部署包上强制250 MB硬上限,而仅一个无头Chromium构建就已经是150 MB到300 MB。 那使得PuppeteerSharp或Playwright的标准zip部署不可行,并将团队推入基于容器的Lambda,尽管冷启动变得较差,但允许最多10 GB。

Azure App Service则为两种操作系统添加了它自己的限制。 Windows App Service沙盒阻止大多数User32和GDI32调用,从而破坏了依赖GDI的渲染路径。 在Linux App Service上部署DinkToPdf意味着要将非托管的libxrender1的依赖; 缺少一个将显示为不透明的System.DllNotFoundException。 这些是验证运行重现的同样的本机依赖和沙盒问题。

结论与建议

在.NET 10上的C# HTML转PDF领域会根据文档匹配工具而得到奖励。 完整的浏览器引擎是CSS框架和响应式布局及JavaScript驱动画页的基准,而免费与商业之间的分裂实际上是运营努力和许可证成本之间的分裂。程序化库在固定、静态布局上保持效率,输入为结构化数据而非标记时,QuestPDF是最快的路线。由于其归档引擎和未修补的SSRF漏洞,wkhtmltopdf只适合于迁移计划。 对于想要精准渲染且不希望过多运维开销的团队,IronPDF是默认嵌入选项,URL到PDFRazor视图渲染PDF/A输出数字签名从同一API可用,而PuppeteerSharp和Playwright在团队可以拥有浏览器生命周期时仍是强大的免费选择。

试用您自己的HTML

若轻量的运输成本与精准的渲染符合您的项目,您可以启动免费的IronPDF试用并在提交之前用您自己的模板运行相同的测试发票。 IronPDF由Iron Software构建,其.NET库还涵盖OCR、条形码、Word和Excel。

感谢阅读。 无论您选择了哪个库,请将其与面前的文档相匹配。

请注意IronPDF是Iron Software的产品。 PuppeteerSharp、Playwright、wkhtmltopdf、DinkToPdf、PdfSharp、HtmlRenderer、QuestPDF和iText是其各自所有者的项目或商标。 本文与这些项目没有关联,不被支持或赞助。 比较反映了撰写时公开可用的信息和亲身实践; 在依赖它们之前请验证当前的许可和发布细节。

常见问题解答

What are the main types of C# HTML to PDF libraries available for .NET 10 in 2026?

The main types of C# HTML to PDF libraries for .NET 10 in 2026 include browser-based engines like Chromium using PuppeteerSharp or Playwright, programmatic libraries such as iText and PdfSharp, and code-first layout tools like QuestPDF.

How do browser-based engines compare to programmatic libraries for HTML to PDF conversion?

Browser-based engines render modern CSS and JavaScript accurately, providing high fidelity to web standards, whereas programmatic libraries like iText and PdfSharp trade some web fidelity for a smaller footprint by drawing PDFs from custom parsers.

What advantages do code-first layout tools offer over traditional HTML to PDF methods?

Code-first layout tools like QuestPDF allow developers to skip HTML entirely, often resulting in more efficient and customizable PDF generation tailored to specific application needs.

Why is choosing the right rendering engine important for HTML to PDF conversion?

Choosing the right rendering engine is crucial because it determines how accurately your documents are rendered, especially in terms of modern CSS and JavaScript fidelity, which is important for maintaining the visual integrity of your PDFs.

What role do licensing terms play in selecting a C# HTML to PDF library?

Licensing terms are important as they dictate what you can legally do with the library, such as distributing the software commercially, and can affect the overall cost and feasibility of using the library in your projects.

Are there free options available for C# HTML to PDF conversion?

Yes, there are free options available, though they may come with limitations in terms of features and support compared to paid alternatives. It's important to weigh these against your project needs.

How do benchmarks help in evaluating C# HTML to PDF libraries?

Benchmarks provide a quantitative measure of performance, allowing developers to compare libraries based on speed, resource usage, and output quality, helping in making an informed decision.

What is the significance of runnable code examples in library comparisons?

Runnable code examples are significant as they allow developers to test libraries in real-world scenarios, providing insights into ease of use, integration complexity, and how well a library fits specific project requirements.

Can IronPDF be a suitable option for HTML to PDF conversion in .NET 10?

Yes, IronPDF is a suitable option, known for its ease of use, comprehensive features, and support for modern web standards, making it a strong contender for HTML to PDF conversion in .NET 10.

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我