跳過到頁腳內容
MIGRATION GUIDES

How to Migrate from PuppeteerSharp to IronPDF in C#

從 傀儡師夏普 遷移到 IronPDF 會將您的 PDF 生成工作流程從一個具有 300MB 以上依賴項的瀏覽器自動化工具轉變為具有自動記憶體管理功能的專用 PDF 庫。 本指南提供完整的、逐步的遷移路徑,消除 Chromium 下載,解決記憶體洩漏問題,並提供全面的 PDF 操作功能。

為什麼要從 傀儡師夏普 遷移到 IronPDF

理解木偶師夏普

PuppeteerSharp 是 Google Puppeteer 的 .NET 移植版,將瀏覽器自動化功能引入 C#。 它使用 Chrome 內建的列印到 PDF 功能來產生 PDF 文件——就像在瀏覽器中按下 Ctrl+P 一樣。 這樣就能產生針對紙張優化的可列印輸出,這與你在螢幕上看到的內容有所不同。

PuppeteerSharp 的設計用途是網頁測試和資料抓取,而不是文件產生。 雖然 傀儡師夏普 能夠產生 PDF 文件,但它會帶來重大的生產挑戰。

瀏覽器自動化問題

PuppeteerSharp 的設計初衷是用於瀏覽器自動化,而不是文件產生。 這會為使用 PDF 文件帶來根本性問題:

  1. 首次使用前需下載 300MB 以上的 Chromium 。 傀儡師夏普 的一個顯著缺點是其部署體積龐大,這主要是由於它捆綁了 Chromium 二進位。 這種巨大的體積會導致 Docker 映像膨脹,並在無伺服器環境中造成冷啟動問題。

2.高負載下出現記憶體洩漏,需要手動回收瀏覽器。 在高負載情況下,PuppeteerSharp 會出現記憶體洩漏問題。 瀏覽器實例不斷累積內存,需要人工幹預進行進程管理和回收。

  1. 具有瀏覽器生命週期管理的複雜非同步模式

4.列印到 PDF 輸出(相當於 Ctrl+P,而不是螢幕截圖)。 佈局可能會重新排版,背景預設可能會省略,並且輸出會分頁以便列印,而不是與瀏覽器視窗相符。

5.不支援 PDF/A 或 PDF/UA合規性要求。 傀儡師夏普 無法產生符合 PDF/A(存檔)或 PDF/UA(無障礙)標準的文件。

6.不允許對 PDF 進行任何操作- 僅產生 PDF,不允許合併/分割/編輯。 雖然 傀儡師夏普 能夠有效率地產生 PDF 文件,但它缺乏對 PDF 文件進行進一步操作(例如合併、分割、保護或編輯 PDF 文件)的功能。

傀儡師夏普 與 IronPDF 的比較

方面 傀儡師夏普 IronPDF
主要目的 瀏覽器自動化 PDF生成
鉻依賴性 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 滿的 滿的 滿的 滿的
傀儡師夏普 有限的 滿的 滿的 待辦的

IronPDF 對 .NET 平台的廣泛支援確保開發人員可以在各種環境中利用它而不會遇到相容性問題,為現代 .NET 應用程式提供靈活的選擇,直至 2025 年和 2026 年。


開始之前

先決條件

  1. .NET 環境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. NuGet 存取權限:能夠安裝 NuGet 套件
  3. 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
SHELL

使用 IronPDF 不需要BrowserFetcher.DownloadAsync() - 渲染引擎會自動打包。

許可證配置

// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

完整 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;
$vbLabelText   $csharpLabel

核心 API 映射

傀儡師夏普 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");
    }
}
$vbLabelText   $csharpLabel

(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");
    }
}
$vbLabelText   $csharpLabel

這個例子展示了架構上的根本差異。 傀儡師夏普 需要六個非同步操作: BrowserFetcher.DownloadAsync() (下載 300MB 以上的 Chromium 內容)、 Puppeteer.LaunchAsync()browser.NewPageAsync()page.SetContentAsync() 、 browser.NewPageAsync() 、 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");
    }
}
$vbLabelText   $csharpLabel

(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");
    }
}
$vbLabelText   $csharpLabel

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"
            }
        });
    }
}
$vbLabelText   $csharpLabel

(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");
    }
}
$vbLabelText   $csharpLabel

此範例展示了兩個庫之間的 PDF 選項映射關係。 傀儡師夏普 使用PdfOptions其中FormatLandscapeMarginOptions包含字串值( &quot;20mm&quot; )。 IronPDF 使用RenderingOptions屬性,其中包含直接的紙張尺寸枚舉、方向枚舉和以毫米為單位的數值邊距值。

關鍵映射:

  • Format = PaperFormat.A4PaperSize = PdfPaperSize.A4
  • Landscape = truePaperOrientation = PdfPaperOrientation.Landscape
  • MarginOptions.Top = &quot;20mm&quot;MarginTop = 20 (數值毫米)

內存洩漏問題

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
}
// ❌ 傀儡師夏普 - 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
}
$vbLabelText   $csharpLabel

IronPDF 無需像 傀儡師夏普 那樣使用瀏覽器池基礎架構:

// 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;
    }
}
$vbLabelText   $csharpLabel

關鍵遷移說明

異步到同步轉換

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;
}
$vbLabelText   $csharpLabel

邊際單位轉換

PuppeteerSharp 使用字串單元; IronPDF 使用數值毫米:

// 傀儡師夏普 - 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;
// 傀儡師夏普 - 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;
$vbLabelText   $csharpLabel

頁首/頁尾佔位符轉換

傀儡師夏普 課程 IronPDF佔位符
<span class="pageNumber"> {page}
<span class="totalPages"> {total-pages}
<span class="date"> {date}
<span class="title"> {html-title}

遷移後的新功能

遷移到 IronPDF 後,您將獲得 傀儡師夏普 無法提供的功能:

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");
$vbLabelText   $csharpLabel

水印

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);
$vbLabelText   $csharpLabel

密碼保護

pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
$vbLabelText   $csharpLabel

數位簽名

var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
$vbLabelText   $csharpLabel

PDF/A 合規性

pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
$vbLabelText   $csharpLabel

性能比較摘要

指標 傀儡師夏普 IronPDF 改進
第一個 PDF(冷啟動) 45歲以上 約20秒 速度提升 55% 以上
後續PDF 多變的 持續的 可預測的
記憶體使用情況 500MB+(持續成長) 約50MB(穩定版) 記憶體減少 90%
磁碟空間(Chromium) 300MB+ 0 取消下載
瀏覽器下載 必需的 不需要 零設定
螺紋安全 有限的 滿的 可靠的並發性
PDF產生時間 45秒 20多歲 速度提升 55%

遷移清單

遷移前

  • 識別程式碼庫中所有 傀儡師夏普 的使用情況
  • 文檔邊距值(將字串轉換為毫米)
  • 注意頁首/頁尾佔位符語法以進行轉換
  • 刪除瀏覽器池/回收基礎設施
  • ironpdf.com取得 IronPDF 許可證金鑰

軟體包變更

  • 刪除PuppeteerSharp NuGet 套件
  • 刪除.local-chromium資料夾以回收約 300MB 磁碟空間 安裝IronPdf NuGet 套件: dotnet add package IronPdf

程式碼更改

  • 更新命名空間匯入
  • 移除BrowserFetcher.DownloadAsync()調用
  • 移除Puppeteer.LaunchAsync()和瀏覽器管理
  • page.SetContentAsync() + page.PdfAsync()替換為RenderHtmlAsPdf()
  • page.GoToAsync() + page.PdfAsync()替換為RenderUrlAsPdf()
  • 將邊距字串轉換為毫米值
  • 轉換頁首/頁尾佔位符語法
  • 刪除所有瀏覽器/頁面銷毀程式碼
  • 刪除瀏覽器池基礎架構
  • 在應用程式啟動時新增許可證初始化

移民後

  • PDF 輸出的視覺比較
  • 記憶體穩定性負載測試(應保持穩定,無需重新啟動)
  • 驗證頁首/頁尾的顯示是否正確,並顯示頁碼
  • 根據需要新增功能(安全性、浮水印、合併)

Curtis Chau
技術撰稿人

Curtis Chau 擁有電腦科學學士學位(卡爾頓大學),專長於前端開發,精通 Node.js、TypeScript、JavaScript 和 React。Curtis 對製作直覺且美觀的使用者介面充滿熱情,他喜歡使用現代化的架構,並製作結構良好且視覺上吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 也有濃厚的興趣,他喜歡探索整合硬體與軟體的創新方式。在空閒時間,他喜歡玩遊戲和建立 Discord bots,將他對技術的熱愛與創意結合。