如何用 C# 从 PuppeteerSharp 迁移到 IronPDF
从PuppeteerSharp迁移到IronPDF可将您的 PDF 生成工作流程从依赖 300MB 以上的浏览器自动化工具转变为具有自动内存管理功能的专用 PDF 库。 本指南提供了一个完整的、循序渐进的迁移路径,可消除 Chromium 下载、解决内存泄漏问题并提供全面的 PDF 操作功能。
为什么要从PuppeteerSharp迁移到 IronPDF.
了解 PuppeteerSharp。
PuppeteerSharp 是 Google 的 Puppeteer 的 .NET 移植版本,将浏览器自动化功能引入 C#。 它使用 Chrome 浏览器内置的打印成 PDF 功能生成 PDF,就像在浏览器中点击 Ctrl+P 一样。 这将产生针对纸张进行优化的可打印输出,与您在屏幕上看到的不同。
PuppeteerSharp 设计用于网络测试和刮擦,而非文档生成。 使用PuppeteerSharp生成 PDF 虽然能够胜任,但也会给制作带来巨大挑战。
浏览器自动化问题
PuppeteerSharp 设计用于浏览器自动化,而非文档生成。 在将其用于 PDF 时,这会产生一些基本问题:
1.首次使用前需要下载 300MB+ Chromium。PuppeteerSharp的一个明显缺点是部署体积庞大,这主要是由于它捆绑了 Chromium 二进制文件。 在无服务器环境中,Docker 镜像文件的体积很大,可能会造成臃肿,并引发冷启动问题。
2.在负载情况下出现内存泄漏,需要手动回收浏览器。 众所周知,PuppeteerSharp 在重载情况下会出现内存泄漏。 浏览器实例内存的积累需要人工干预进行流程管理和回收。
3.复杂的异步模式与浏览器生命周期管理。
4.打印成 PDF 输出(相当于 Ctrl+P,而不是屏幕截图)。 布局可能会回流,默认情况下背景可能会被省略,输出结果将分页打印,而不是与浏览器视口相匹配。
5.不支持 PDF/A 或 PDF/UA,以满足合规要求。PuppeteerSharp无法生成符合 PDF/A(存档)或 PDF/UA(可访问性)标准的文档。
6.无 PDF 操作 - 仅生成,无合并/拆分/编辑。 虽然PuppeteerSharp能高效生成 PDF,但它缺乏进一步操作的功能,如合并、分割、保护或编辑 PDF。
PuppeteerSharp与IronPDF对比
| 方面 | PuppeteerSharp | IronPDF |
|---|---|---|
| 主要目的 | 浏览器自动化 | 生成 PDF |
| Chromium 依赖性 | 300MB+ 单独下载 | 内置优化引擎 |
| API 复杂性 | 异步浏览器/页面生命周期 | 同步单行本 |
| 初始化 | BrowserFetcher.DownloadAsync() + LaunchAsync |
new ChromePdfRenderer() |
| 内存管理 | 需要手动回收浏览器 | 自动翻译 |
| 负载下的内存 | 500MB+ 有泄露 | ~50MB 稳定 |
| 冷启动 | 45 秒以上 | ~20 秒 |
| PDF/A支持 | 不可用 | 支持 |
| PDF/UA 辅助功能 | 不可用 | 支持 |
| PDF 编辑 | 不可用 | 合并、拆分、盖章、编辑 |
| 数字签名 | 不可用 | 支持 |
| 线程安全 | 有限的 | 满的 |
| 专业支持 | 社区 | 有服务水平协议的商业翻译 |
平台支持
|库|.NET Framework 4.7.2|.NET Core 3.1|.NET 6-8|.NET 10| | --------- | :---: | :---: | :---: | :---: ||IronPDF| 满的 | 满的 | 满的 | 满的 ||PuppeteerSharp| 有限的 | 满的 | 满的 | 待办的 | IronPDF 广泛支持各种 .NET 平台,确保开发人员可以在各种环境中使用它,而不会遇到兼容性问题,为 2025 年和 2026 年的现代 .NET 应用程序提供了灵活的选择。
开始之前
前提条件
- .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 访问权限:能够安装 NuGet 包
- IronPDF 许可证:请从ironpdf.com获取您的许可证密钥。
NuGet 软件包变更
# Remove PuppeteerSharp
dotnet remove package PuppeteerSharp
# Remove downloaded Chromium binaries (~300MB recovered)
# Delete the .local-chromium folder
# Add IronPDF
dotnet add package IronPdf
# Remove PuppeteerSharp
dotnet remove package PuppeteerSharp
# Remove downloaded Chromium binaries (~300MB recovered)
# Delete the .local-chromium folder
# Add IronPDF
dotnet add package IronPdf
IronPDF 不需要 BrowserFetcher.DownloadAsync() - 渲染引擎会自动捆绑。
许可配置
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
完整的 API 参考
命名空间变更
// Before: PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
// Before: PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
' Before: PuppeteerSharp
Imports PuppeteerSharp
Imports PuppeteerSharp.Media
Imports System.Threading.Tasks
' After: IronPDF
Imports IronPdf
Imports IronPdf.Rendering
核心 API 映射
| PuppeteerSharp API | IronPDF API | 备注 |
|---|---|---|
new BrowserFetcher().DownloadAsync() |
不需要 | 无需下载浏览器 |
Puppeteer.LaunchAsync(options) |
不需要 | 无浏览器管理 |
browser.NewPageAsync() |
不需要 | 无页面上下文 |
page.GoToAsync(url) |
renderer.RenderUrlAsPdf(url) |
直接渲染 |
page.SetContentAsync(html) |
renderer.RenderHtmlAsPdf(html) |
直接渲染 |
page.PdfAsync(path) |
pdf.SaveAs(path) |
渲染后 |
await page.CloseAsync() |
不需要 | 自动清理 |
await browser.CloseAsync() |
不需要 | 自动清理 |
PdfOptions.Format |
RenderingOptions.PaperSize |
纸张大小 |
PdfOptions.Landscape |
RenderingOptions.PaperOrientation |
定位 |
PdfOptions.MarginOptions |
RenderingOptions.MarginTop/Bottom/Left/Right |
个别页边距 |
PdfOptions.PrintBackground |
RenderingOptions.PrintHtmlBackgrounds |
背景打印 |
PdfOptions.HeaderTemplate |
RenderingOptions.HtmlHeader |
HTML 标题 |
PdfOptions.FooterTemplate |
RenderingOptions.HtmlFooter |
HTML 页脚 |
page.WaitForSelectorAsync() |
RenderingOptions.WaitFor.HtmlElementId |
等待元素 |
代码迁移示例
示例 1:基本 HTML 到 PDF 的转换
之前(PuppeteerSharp):
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Hello World</h1><p>This is a PDF document.</p>");
await page.PdfAsync("output.pdf");
}
}
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Hello World</h1><p>This is a PDF document.</p>");
await page.PdfAsync("output.pdf");
}
}
Imports PuppeteerSharp
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim browserFetcher = New BrowserFetcher()
Await browserFetcher.DownloadAsync()
Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
.Headless = True
})
Using page = Await browser.NewPageAsync()
Await page.SetContentAsync("<h1>Hello World</h1><p>This is a PDF document.</p>")
Await page.PdfAsync("output.pdf")
End Using
End Using
End Function
End Module
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF document.</p>");
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF document.</p>");
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main(args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF document.</p>")
pdf.SaveAs("output.pdf")
End Sub
End Class
本例展示了基本的架构差异。PuppeteerSharp需要六个异步操作:BrowserFetcher.DownloadAsync()(300MB+ Chromium 下载),Puppeteer.LaunchAsync(),browser.NewPageAsync(),page.SetContentAsync(),以及 page.PdfAsync(),以及使用 await using 进行适当的处置。
IronPDF 消除了所有这些复杂性:创建一个 ChromePdfRenderer,调用 RenderHtmlAsPdf(),以及 SaveAs()。 没有异步模式,没有浏览器生命周期,没有 Chromium 下载。IronPDF的方法提供了更简洁的语法和与现代 .NET 应用程序更好的集成。 请参阅 HTML 转 PDF 文档,了解全面的示例。
示例 2:URL 到 PDF 的转换
之前(PuppeteerSharp):
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.GoToAsync("https://www.example.com");
await page.PdfAsync("webpage.pdf");
}
}
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.GoToAsync("https://www.example.com");
await page.PdfAsync("webpage.pdf");
}
}
Imports PuppeteerSharp
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim browserFetcher = New BrowserFetcher()
Await browserFetcher.DownloadAsync()
Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
.Headless = True
})
Using page = Await browser.NewPageAsync()
Await page.GoToAsync("https://www.example.com")
Await page.PdfAsync("webpage.pdf")
End Using
End Using
End Function
End Module
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
PuppeteerSharp 使用 GoToAsync() 导航到 URL,然后使用 PdfAsync()。IronPDF提供了一个单一的 RenderUrlAsPdf() 方法,可以在一次调用中处理导航和 PDF 生成。 在我们的教程中了解更多信息。
示例 3:带边距的自定义页面设置
之前(PuppeteerSharp):
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
await page.PdfAsync("custom.pdf", new PdfOptions
{
Format = PaperFormat.A4,
Landscape = true,
MarginOptions = new MarginOptions
{
Top = "20mm",
Bottom = "20mm",
Left = "20mm",
Right = "20mm"
}
});
}
}
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
await page.PdfAsync("custom.pdf", new PdfOptions
{
Format = PaperFormat.A4,
Landscape = true,
MarginOptions = new MarginOptions
{
Top = "20mm",
Bottom = "20mm",
Left = "20mm",
Right = "20mm"
}
});
}
}
Imports PuppeteerSharp
Imports PuppeteerSharp.Media
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim browserFetcher = New BrowserFetcher()
Await browserFetcher.DownloadAsync()
Await Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
.Headless = True
})
Await Using page = Await browser.NewPageAsync()
Await page.SetContentAsync("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>")
Await page.PdfAsync("custom.pdf", New PdfOptions With {
.Format = PaperFormat.A4,
.Landscape = True,
.MarginOptions = New MarginOptions With {
.Top = "20mm",
.Bottom = "20mm",
.Left = "20mm",
.Right = "20mm"
}
})
End Using
End Using
End Function
End Module
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
pdf.SaveAs("custom.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
pdf.SaveAs("custom.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main(args As String())
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
renderer.RenderingOptions.MarginLeft = 20
renderer.RenderingOptions.MarginRight = 20
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>")
pdf.SaveAs("custom.pdf")
End Sub
End Class
本例展示了 PDF 选项如何在两个库之间映射。PuppeteerSharp使用 PdfOptions,其中 Format、Landscape 和 MarginOptions 包含字符串值 ("20mm")。IronPDF使用 RenderingOptions 属性,其中包含直接的纸张尺寸枚举、方向枚举和以毫米为单位的数值边距值。
关键映射:
Format = PaperFormat.A4→PaperSize = PdfPaperSize.A4Landscape = true→PaperOrientation = PdfPaperOrientation.LandscapeMarginOptions.Top = "20mm"→MarginTop = 20(数值毫米)
内存泄漏问题
PuppeteerSharp 在持续负载的情况下内存累积是出了名的:
// ❌PuppeteerSharp- Memory grows with each operation
// Requires explicit browser recycling every N operations
for (int i = 0; i < 1000; i++)
{
var page = await browser.NewPageAsync();
await page.SetContentAsync($"<h1>Document {i}</h1>");
await page.PdfAsync($"doc_{i}.pdf");
await page.CloseAsync(); // Memory still accumulates!
}
// Must periodically: await browser.CloseAsync(); and re-launch
// ✅IronPDF- Stable memory, reuse renderer
var renderer = new ChromePdfRenderer();
for (int i = 0; i < 1000; i++)
{
var pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>");
pdf.SaveAs($"doc_{i}.pdf");
// Memory managed automatically
}
// ❌PuppeteerSharp- Memory grows with each operation
// Requires explicit browser recycling every N operations
for (int i = 0; i < 1000; i++)
{
var page = await browser.NewPageAsync();
await page.SetContentAsync($"<h1>Document {i}</h1>");
await page.PdfAsync($"doc_{i}.pdf");
await page.CloseAsync(); // Memory still accumulates!
}
// Must periodically: await browser.CloseAsync(); and re-launch
// ✅IronPDF- Stable memory, reuse renderer
var renderer = new ChromePdfRenderer();
for (int i = 0; i < 1000; i++)
{
var pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>");
pdf.SaveAs($"doc_{i}.pdf");
// Memory managed automatically
}
' ❌PuppeteerSharp- Memory grows with each operation
' Requires explicit browser recycling every N operations
For i As Integer = 0 To 999
Dim page = Await browser.NewPageAsync()
Await page.SetContentAsync($"<h1>Document {i}</h1>")
Await page.PdfAsync($"doc_{i}.pdf")
Await page.CloseAsync() ' Memory still accumulates!
Next
' Must periodically: Await browser.CloseAsync() and re-launch
' ✅IronPDF- Stable memory, reuse renderer
Dim renderer As New ChromePdfRenderer()
For i As Integer = 0 To 999
Dim pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>")
pdf.SaveAs($"doc_{i}.pdf")
' Memory managed automatically
Next
IronPDF 不需要PuppeteerSharp所需的浏览器池基础设施:
// Before (PuppeteerSharp - delete entire class)
public class PuppeteerBrowserPool
{
private readonly ConcurrentBag<IBrowser> _browsers;
private readonly SemaphoreSlim _semaphore;
private int _operationCount;
// ... recycling logic ...
}
// After (IronPDF - simple reuse)
public class PdfService
{
private readonly ChromePdfRenderer _renderer = new();
public byte[] Generate(string html)
{
return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
}
// Before (PuppeteerSharp - delete entire class)
public class PuppeteerBrowserPool
{
private readonly ConcurrentBag<IBrowser> _browsers;
private readonly SemaphoreSlim _semaphore;
private int _operationCount;
// ... recycling logic ...
}
// After (IronPDF - simple reuse)
public class PdfService
{
private readonly ChromePdfRenderer _renderer = new();
public byte[] Generate(string html)
{
return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
}
' Before (PuppeteerSharp - delete entire class)
Public Class PuppeteerBrowserPool
Private ReadOnly _browsers As ConcurrentBag(Of IBrowser)
Private ReadOnly _semaphore As SemaphoreSlim
Private _operationCount As Integer
' ... recycling logic ...
End Class
' After (IronPDF - simple reuse)
Public Class PdfService
Private ReadOnly _renderer As New ChromePdfRenderer()
Public Function Generate(html As String) As Byte()
Return _renderer.RenderHtmlAsPdf(html).BinaryData
End Function
End Class
关键迁移说明
同步到同步转换
PuppeteerSharp 自始至终需要 async/await;IronPDF支持同步操作:
// PuppeteerSharp: Async required
public async Task<byte[]> GeneratePdfAsync(string html)
{
await new BrowserFetcher().DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(...);
await using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
return await page.PdfDataAsync();
}
// IronPDF: Sync default
public byte[] GeneratePdf(string html)
{
var renderer = new ChromePdfRenderer();
return renderer.RenderHtmlAsPdf(html).BinaryData;
}
// Or async when needed
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
// PuppeteerSharp: Async required
public async Task<byte[]> GeneratePdfAsync(string html)
{
await new BrowserFetcher().DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(...);
await using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
return await page.PdfDataAsync();
}
// IronPDF: Sync default
public byte[] GeneratePdf(string html)
{
var renderer = new ChromePdfRenderer();
return renderer.RenderHtmlAsPdf(html).BinaryData;
}
// Or async when needed
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
Imports System.Threading.Tasks
Imports PuppeteerSharp
' PuppeteerSharp: Async required
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Await (New BrowserFetcher()).DownloadAsync()
Await Using browser = Await Puppeteer.LaunchAsync(...)
Await Using page = Await browser.NewPageAsync()
Await page.SetContentAsync(html)
Return Await page.PdfDataAsync()
End Using
End Using
End Function
' IronPDF: Sync default
Public Function GeneratePdf(html As String) As Byte()
Dim renderer = New ChromePdfRenderer()
Return renderer.RenderHtmlAsPdf(html).BinaryData
End Function
' Or async when needed
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Function
边际单位转换
PuppeteerSharp 使用字符串单位;IronPDF使用数字毫米:
//PuppeteerSharp- string units
MarginOptions = new MarginOptions
{
Top = "1in", // 25.4mm
Bottom = "0.75in", // 19mm
Left = "1cm", // 10mm
Right = "20px" // ~7.5mm at 96dpi
}
//IronPDF- numeric millimeters
renderer.RenderingOptions.MarginTop = 25; // mm
renderer.RenderingOptions.MarginBottom = 19;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 8;
//PuppeteerSharp- string units
MarginOptions = new MarginOptions
{
Top = "1in", // 25.4mm
Bottom = "0.75in", // 19mm
Left = "1cm", // 10mm
Right = "20px" // ~7.5mm at 96dpi
}
//IronPDF- numeric millimeters
renderer.RenderingOptions.MarginTop = 25; // mm
renderer.RenderingOptions.MarginBottom = 19;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 8;
MarginOptions = New MarginOptions With {
.Top = "1in", ' 25.4mm
.Bottom = "0.75in", ' 19mm
.Left = "1cm", ' 10mm
.Right = "20px" ' ~7.5mm at 96dpi
}
renderer.RenderingOptions.MarginTop = 25 ' mm
renderer.RenderingOptions.MarginBottom = 19
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 8
页眉/页脚占位符转换
| PuppeteerSharp 类 | IronPDF 占位符 |
|---|---|
<span class='pageNumber'> |
{page} |
<span class='totalPages'> |
{total-pages} |
<span class='date'> |
{date} |
<span class='title'> |
{html-title} |
迁移后的新功能
迁移到IronPDF后,您将获得PuppeteerSharp无法提供的功能:
PDF 合并
var pdf1 = renderer.RenderHtmlAsPdf(html1);
var pdf2 = renderer.RenderHtmlAsPdf(html2);
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
var pdf1 = renderer.RenderHtmlAsPdf(html1);
var pdf2 = renderer.RenderHtmlAsPdf(html2);
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
Dim pdf1 = renderer.RenderHtmlAsPdf(html1)
Dim pdf2 = renderer.RenderHtmlAsPdf(html2)
Dim merged = PdfDocument.Merge(pdf1, pdf2)
merged.SaveAs("merged.pdf")
水印
var watermark = new TextStamper
{
Text = "CONFIDENTIAL",
FontSize = 48,
Opacity = 30,
Rotation = -45
};
pdf.ApplyStamp(watermark);
var watermark = new TextStamper
{
Text = "CONFIDENTIAL",
FontSize = 48,
Opacity = 30,
Rotation = -45
};
pdf.ApplyStamp(watermark);
Dim watermark As New TextStamper With {
.Text = "CONFIDENTIAL",
.FontSize = 48,
.Opacity = 30,
.Rotation = -45
}
pdf.ApplyStamp(watermark)
密码保护
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.OwnerPassword = "admin"
pdf.SecuritySettings.UserPassword = "readonly"
pdf.SecuritySettings.AllowUserCopyPasteContent = False
数字签名
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)
PDF/A 合规性
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b)
性能比较摘要
| 指标 | PuppeteerSharp | IronPDF | 改进 |
|---|---|---|---|
| 第一个 PDF(冷启动) | 45s+ | ~20s | 速度提高 55% 以上。 |
| 后续 PDF | 变量 | 一致性 | 可预测性 |
| 内存使用情况 | 500MB+(增长) | ~50MB(稳定) | 减少 90% 内存 |
| 磁盘空间(Chromium) | 300MB 以上 | 0 | 取消下载。 |
| 浏览器下载 | 要求 | 不需要 | 零设置 |
| 线程安全 | 有限的 | 满的 | 可靠的并发性 |
| PDF 生成时间 | 45s | 20s | 速度提高 55% |
迁移清单
迁移前
- 识别代码库中所有PuppeteerSharp的使用情况
- 文档边距值(将字符串转换为毫米)
- 注意页眉/页脚占位符语法以进行转换
- 删除浏览器池/回收基础设施
- 从ironpdf.com获取IronPDF许可证密钥
软件包变更
- 删除
PuppeteerSharpNuGet 包 - 删除
.local-chromium文件夹以回收约 300MB 磁盘空间 安装IronPdfNuGet 包:dotnet add package IronPdf
代码更改
- 更新命名空间导入
- 删除
BrowserFetcher.DownloadAsync()调用 - 移除
Puppeteer.LaunchAsync()和浏览器管理 - 将
page.SetContentAsync()+page.PdfAsync()替换为RenderHtmlAsPdf() - 将
page.GoToAsync()+page.PdfAsync()替换为RenderUrlAsPdf() - 将边距字符串转换为毫米值
- 转换页眉/页脚占位符语法
- 删除所有浏览器/页面销毁代码
- 删除浏览器池基础架构
- 在应用程序启动时添加许可证初始化
后迁移
- PDF 输出的视觉比较
- 内存稳定性负载测试(应保持稳定,无需重启)
- 验证页眉/页脚的显示是否正确,并显示页码
- 根据需要添加新功能(安全、水印、合并)

