跳至頁尾內容
影片

如何在 NET MAUI 中將 XAML 轉換為 PDF | IronPDF

從Spire.PDF遷移到IronPDF,可將您的PDF生成移出經常生成基於圖像文字的遺留HTML路徑,改為使用產生真實、可選擇、可搜尋文字的Chromium管道。 本指南提供了完整的逐步遷移路徑,涵蓋Spire.PDF的HTML渲染權衡和已知的字體嵌入問題。

為什麼從Spire.PDF遷移到IronPDF

了解Spire.PDF

Spire.PDF是一個功能強大的商業PDF程式庫,專為.NET開發人員設計,以高效處理PDF文件。 Spire.PDF已經在程式設計社群中因其特定功能,特別是在遺留應用程式中受到關注,並且其整合能力與E-iceblue工具集的其他元件無縫對接。

然而,Spire.PDF存在若干基本問題,影響其在實際使用中的效果,特別是在HTML到PDF轉換和現代網路標準支持方面。

關鍵技術問題

問題 影響 IronPDF解決方案
經常在遺留HTML路徑中將文字呈現為圖像 無法搜尋的PDF,無法存取,無法複製文字 真實文字渲染
IE/Edge遺留或QtWebKit在遺留路徑上的依賴 過時渲染,現代CSS問題 捆綁的現代Chromium
已報告的字體嵌入問題 文件在其他系統上顯示不正確 可靠的字體處理
大的部署佔地 更高的記憶體使用量 捆綁的Chromium運行時
遺留路徑上的CSS有限 現代佈局無法正確渲染 完整的CSS3支持

核心問題:基於圖像的PDF

已知Spire.PDF的遺留HTML路徑的一個缺點是它傾向於將HTML文件中的文字呈現為圖像。 這產生了PDF,文字無法選擇或搜索——這對於需要搜索或文字交互的應用程式來說是一個限制。

當您在遺留引擎上使用Spire.PDF的LoadFromHTML()方法時,它經常將文字呈現為位圖圖像而不是實際文字,從而產生這些問題:

  • 文字不能被選擇
  • 文字不能被搜索
  • 文字不能被複製
  • 螢幕閱讀器不能讀取它(可及性違規)
  • 文件大小大得多
  • 放大時會導致像素化

Spire.PDF與IronPDF比較

功能 Spire.PDF IronPDF
HTML到PDF渲染 預設使用遺留IE/QtWebKit; 從v10.7.21開始,選擇取消ChromeHtmlConverter(需要系統Chrome) 捆綁的Chromium(現代,無需額外安裝)
文字輸出(HTML路徑) 通常在遺留路徑上呈現為圖像 真實文字(可選擇和可搜尋)
字體處理 遺留路徑上已報告問題 可靠的字體處理
CSS3支援 遺留路徑上的限制 全面
Flexbox/Grid 遺留路徑不支持 支援
JavaScript 遺留路徑上的限制 完整ES6+
PDF可達性 遺留路徑(基於圖像的輸出)很差 標記文字的輸出
API設計 多重重載,手動頁面設置 單一流暢渲染器
授權 免費/商業 商業

在現代.NET上,IronPDF通過將文字呈現為選擇性文字而非圖像來解決Spire.PDF的HTML到PDF折衷,從而使生成的PDF可搜尋和可及性。


開始之前

前提條件

  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 Spire.PDF
dotnet remove package Spire.PDF
dotnet remove package FreeSpire.PDF  # If using free version

# Install IronPDF
dotnet add package IronPdf
# Remove Spire.PDF
dotnet remove package Spire.PDF
dotnet remove package FreeSpire.PDF  # If using free version

# Install IronPDF
dotnet add package IronPdf
SHELL

授權配置

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

完整API參考

名稱空間變更

// Before: Spire.PDF
using Spire.Pdf;
using Spire.Pdf.Graphics;
using Spire.Pdf.HtmlConverter;

// After: IronPDF
using IronPdf;
using IronPdf.Editing;
// Before: Spire.PDF
using Spire.Pdf;
using Spire.Pdf.Graphics;
using Spire.Pdf.HtmlConverter;

// After: IronPDF
using IronPdf;
using IronPdf.Editing;
Imports IronPdf
Imports IronPdf.Editing
$vbLabelText   $csharpLabel

核心API對應

Spire.PDF IronPDF
new PdfDocument() new ChromePdfRenderer()
pdf.LoadFromHTML() renderer.RenderHtmlAsPdf()
pdf.LoadFromFile() PdfDocument.FromFile()
pdf.SaveToFile() pdf.SaveAs()
pdf.Close() 不需要
pdf.Pages.Add() renderer.RenderHtmlAsPdf()
pdf.InsertPageRange() PdfDocument.Merge()
page.Canvas.DrawString() TextStamper + ApplyStamp()
PdfFont HTML中的CSS樣式
PdfBrush HTML中的CSS樣式

程式碼遷移範例

範例1:HTML轉PDF轉換

之前(Spire.PDF):

// NuGet: Install-Package Spire.PDF
using Spire.Pdf;
using Spire.Pdf.Graphics;
using System;

class Program
{
    static void Main()
    {
        PdfDocument pdf = new PdfDocument();
        PdfHtmlLayoutFormat htmlLayoutFormat = new PdfHtmlLayoutFormat();

        string htmlString = "<html><body><h1>Hello World</h1><p>This is a PDF from HTML.</p></body></html>";

        pdf.LoadFromHTML(htmlString, false, true, true);
        pdf.SaveToFile("output.pdf");
        pdf.Close();
    }
}
// NuGet: Install-Package Spire.PDF
using Spire.Pdf;
using Spire.Pdf.Graphics;
using System;

class Program
{
    static void Main()
    {
        PdfDocument pdf = new PdfDocument();
        PdfHtmlLayoutFormat htmlLayoutFormat = new PdfHtmlLayoutFormat();

        string htmlString = "<html><body><h1>Hello World</h1><p>This is a PDF from HTML.</p></body></html>";

        pdf.LoadFromHTML(htmlString, false, true, true);
        pdf.SaveToFile("output.pdf");
        pdf.Close();
    }
}
Imports Spire.Pdf
Imports Spire.Pdf.Graphics
Imports System

Class Program
    Shared Sub Main()
        Dim pdf As New PdfDocument()
        Dim htmlLayoutFormat As New PdfHtmlLayoutFormat()

        Dim htmlString As String = "<html><body><h1>Hello World</h1><p>This is a PDF from HTML.</p></body></html>"

        pdf.LoadFromHTML(htmlString, False, True, True)
        pdf.SaveToFile("output.pdf")
        pdf.Close()
    End Sub
End Class
$vbLabelText   $csharpLabel

之後(IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();

        string htmlString = "<html><body><h1>Hello World</h1><p>This is a PDF from HTML.</p></body></html>";

        var pdf = renderer.RenderHtmlAsPdf(htmlString);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();

        string htmlString = "<html><body><h1>Hello World</h1><p>This is a PDF from HTML.</p></body></html>";

        var pdf = renderer.RenderHtmlAsPdf(htmlString);
        pdf.SaveAs("output.pdf");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()

        Dim htmlString As String = "<html><body><h1>Hello World</h1><p>This is a PDF from HTML.</p></body></html>"

        Dim pdf = renderer.RenderHtmlAsPdf(htmlString)
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

此範例演示了HTML渲染的基本差異。 Spire.PDF使用PdfHtmlLayoutFormat物件,經常將文字呈現為位圖圖像。 結果是PDF,使用者無法選擇、複製或搜索文字。

IronPDF使用RenderHtmlAsPdf(),生成完全可選擇、可搜索和可及性的真實文字。 不需要Close()調用——IronPDF使用dispose模式進行自動清理。參見HTML到PDF文件中的完整範例。

範例2:合併多個PDF

之前(Spire.PDF):

// NuGet: Install-Package Spire.PDF
using Spire.Pdf;
using System;

class Program
{
    static void Main()
    {
        PdfDocument pdf1 = new PdfDocument();
        pdf1.LoadFromFile("document1.pdf");

        PdfDocument pdf2 = new PdfDocument();
        pdf2.LoadFromFile("document2.pdf");

        pdf1.InsertPageRange(pdf2, 0, pdf2.Pages.Count - 1);

        pdf1.SaveToFile("merged.pdf");
        pdf1.Close();
        pdf2.Close();
    }
}
// NuGet: Install-Package Spire.PDF
using Spire.Pdf;
using System;

class Program
{
    static void Main()
    {
        PdfDocument pdf1 = new PdfDocument();
        pdf1.LoadFromFile("document1.pdf");

        PdfDocument pdf2 = new PdfDocument();
        pdf2.LoadFromFile("document2.pdf");

        pdf1.InsertPageRange(pdf2, 0, pdf2.Pages.Count - 1);

        pdf1.SaveToFile("merged.pdf");
        pdf1.Close();
        pdf2.Close();
    }
}
Imports Spire.Pdf
Imports System

Class Program
    Shared Sub Main()
        Dim pdf1 As New PdfDocument()
        pdf1.LoadFromFile("document1.pdf")

        Dim pdf2 As New PdfDocument()
        pdf2.LoadFromFile("document2.pdf")

        pdf1.InsertPageRange(pdf2, 0, pdf2.Pages.Count - 1)

        pdf1.SaveToFile("merged.pdf")
        pdf1.Close()
        pdf2.Close()
    End Sub
End Class
$vbLabelText   $csharpLabel

之後(IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var pdf1 = PdfDocument.FromFile("document1.pdf");
        var pdf2 = PdfDocument.FromFile("document2.pdf");

        var merged = PdfDocument.Merge(pdf1, pdf2);

        merged.SaveAs("merged.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var pdf1 = PdfDocument.FromFile("document1.pdf");
        var pdf2 = PdfDocument.FromFile("document2.pdf");

        var merged = PdfDocument.Merge(pdf1, pdf2);

        merged.SaveAs("merged.pdf");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim pdf1 = PdfDocument.FromFile("document1.pdf")
        Dim pdf2 = PdfDocument.FromFile("document2.pdf")

        Dim merged = PdfDocument.Merge(pdf1, pdf2)

        merged.SaveAs("merged.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

Spire.PDF需要手動載入每個文件,使用new PdfDocument() + Close()

IronPDF使用更簡單的PdfDocument.Merge()方法。 不需要Close()調用。 在我們的教程中了解更多。

範例3:向PDF新增文字

之前(Spire.PDF):

// NuGet: Install-Package Spire.PDF
using Spire.Pdf;
using Spire.Pdf.Graphics;
using System.Drawing;
using System;

class Program
{
    static void Main()
    {
        PdfDocument pdf = new PdfDocument();
        PdfPageBase page = pdf.Pages.Add();

        PdfFont font = new PdfFont(PdfFontFamily.Helvetica, 20);
        PdfBrush brush = new PdfSolidBrush(Color.Black);

        page.Canvas.DrawString("Hello from Spire.PDF!", font, brush, new PointF(50, 50));

        pdf.SaveToFile("output.pdf");
        pdf.Close();
    }
}
// NuGet: Install-Package Spire.PDF
using Spire.Pdf;
using Spire.Pdf.Graphics;
using System.Drawing;
using System;

class Program
{
    static void Main()
    {
        PdfDocument pdf = new PdfDocument();
        PdfPageBase page = pdf.Pages.Add();

        PdfFont font = new PdfFont(PdfFontFamily.Helvetica, 20);
        PdfBrush brush = new PdfSolidBrush(Color.Black);

        page.Canvas.DrawString("Hello from Spire.PDF!", font, brush, new PointF(50, 50));

        pdf.SaveToFile("output.pdf");
        pdf.Close();
    }
}
Imports Spire.Pdf
Imports Spire.Pdf.Graphics
Imports System.Drawing
Imports System

Class Program
    Shared Sub Main()
        Dim pdf As New PdfDocument()
        Dim page As PdfPageBase = pdf.Pages.Add()

        Dim font As New PdfFont(PdfFontFamily.Helvetica, 20)
        Dim brush As PdfBrush = New PdfSolidBrush(Color.Black)

        page.Canvas.DrawString("Hello from Spire.PDF!", font, brush, New PointF(50, 50))

        pdf.SaveToFile("output.pdf")
        pdf.Close()
    End Sub
End Class
$vbLabelText   $csharpLabel

之後(IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Editing;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<html><body></body></html>");

        var textStamper = new TextStamper()
        {
            Text = "Hello from IronPDF!",
            FontSize = 20,
            VerticalOffset = 50,
            HorizontalOffset = 50
        };

        pdf.ApplyStamp(textStamper);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Editing;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<html><body></body></html>");

        var textStamper = new TextStamper()
        {
            Text = "Hello from IronPDF!",
            FontSize = 20,
            VerticalOffset = 50,
            HorizontalOffset = 50
        };

        pdf.ApplyStamp(textStamper);
        pdf.SaveAs("output.pdf");
    }
}
Imports IronPdf
Imports IronPdf.Editing
Imports System

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf("<html><body></body></html>")

        Dim textStamper = New TextStamper() With {
            .Text = "Hello from IronPDF!",
            .FontSize = 20,
            .VerticalOffset = 50,
            .HorizontalOffset = 50
        }

        pdf.ApplyStamp(textStamper)
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

Spire.PDF使用基於畫布的繪圖模型,搭配PointF將文字定位在特定座標。

IronPDF使用帶有直觀屬性的ApplyStamp()應用它。 這種方法更具宣告性且易於維護。


文字作為圖像問題

為什麼這很重要

當Spire.PDF使用基於圖像的渲染器將HTML轉換為PDF時,您的文件將失去關鍵功能:

1. 無文字搜尋:使用者無法使用Ctrl+F查找文字。 文件管理系統無法索引內容。

2. 無文字選擇/複製:嘗試複製引用、參考或資料的使用者無法選擇文字——這是張圖像。

3. 可及性違規:基於圖像的PDF不符合WCAG 2.1規範、美國政府508條款、ADA要求以及螢幕閱讀器相容性。

4. 大文件大小:從遺留HTML路徑生成的基於圖像的輸出文件比IronPDF生成的相同內容的基於文字的輸出大得多。

檢測:您的PDF是否基於圖像?

打開您由Spire.PDF生成的文件,嘗試以下測試:

  1. 文字選擇:單擊並拖曳文字。 如果沒有高亮顯示 → 基於圖像
  2. Ctrl+F搜尋:在頁面上搜尋任何詞。 如果顯示"未發現匹配" → 基於圖像
  3. 複製/粘貼:選擇並將文字複製到記事本。 如果沒有任何粘貼 → 基於圖像

遺留HTML引擎問題

Spire.PDF的渲染引擎

Spire.PDF的LoadFromHTML(...)歷史上提供了兩條路徑:由Windows Internet Explorer/Edge遺留WebBrowser控制支援的非插件路徑,以及需要單獨下載的QT/WebKit插件路徑。 Spire.PDF 10.7.21(2024年中)增加了第三個選項ChromeHtmlConverter,它可以調用本地安裝的Google Chrome——但這需要選擇加入,而原本的LoadFromHTMLAPI仍然預設為遺留引擎。 Microsoft於2022年廢棄IE/Edge遺留版,現代CSS在遺留路徑上不可靠,JavaScript支持部分且渲染在不同系統上可能有所不同。

Spire.PDF中失敗的現代CSS


<div style="display: flex; justify-content: space-between; gap: 20px;">
    <div style="flex: 1;">Column 1</div>
    <div style="flex: 1;">Column 2</div>
</div>

<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">
    <div>Item 1</div>
    <div>Item 2</div>
    <div>Item 3</div>
</div>

<style>
:root { --primary-color: #007bff; }
h1 { color: var(--primary-color); }
</style>

<div style="display: flex; justify-content: space-between; gap: 20px;">
    <div style="flex: 1;">Column 1</div>
    <div style="flex: 1;">Column 2</div>
</div>

<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">
    <div>Item 1</div>
    <div>Item 2</div>
    <div>Item 3</div>
</div>

<style>
:root { --primary-color: #007bff; }
h1 { color: var(--primary-color); }
</style>
HTML

IronPDF使用現代Chromium渲染,因此所有這些CSS功能都能正確運行。


遷移後的新能力

遷移到IronPDF後,您將獲得Spire.PDF無法提供的功能:

可選擇、可搜尋的文字

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Important Contract</h1>");
pdf.SaveAs("contract.pdf");

// Result:
// ✅ Text is fully selectable
// ✅ Text is searchable with Ctrl+F
// ✅ Text can be copied to clipboard
// ✅ Screen readers work perfectly
// ✅ File size is compact
// ✅ Zooming is crystal clear
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Important Contract</h1>");
pdf.SaveAs("contract.pdf");

// Result:
// ✅ Text is fully selectable
// ✅ Text is searchable with Ctrl+F
// ✅ Text can be copied to clipboard
// ✅ Screen readers work perfectly
// ✅ File size is compact
// ✅ Zooming is crystal clear
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Important Contract</h1>")
pdf.SaveAs("contract.pdf")

' Result:
' ✅ Text is fully selectable
' ✅ Text is searchable with Ctrl+F
' ✅ Text can be copied to clipboard
' ✅ Screen readers work perfectly
' ✅ File size is compact
' ✅ Zooming is crystal clear
$vbLabelText   $csharpLabel

現代CSS支持

var renderer = new ChromePdfRenderer();

var html = @"
<style>
    :root { --primary: #007bff; }
    .container { display: flex; gap: 20px; }
    .grid { display: grid; grid-template-columns: repeat(3, 1fr); }
</style>
<div class='container'>
    <div style='flex: 1; color: var(--primary)'>Column 1</div>
    <div style='flex: 1'>Column 2</div>
</div>
<div class='grid'>
    <div>Item 1</div>
    <div>Item 2</div>
    <div>Item 3</div>
</div>";

var pdf = renderer.RenderHtmlAsPdf(html);
// All modern CSS features render correctly!
var renderer = new ChromePdfRenderer();

var html = @"
<style>
    :root { --primary: #007bff; }
    .container { display: flex; gap: 20px; }
    .grid { display: grid; grid-template-columns: repeat(3, 1fr); }
</style>
<div class='container'>
    <div style='flex: 1; color: var(--primary)'>Column 1</div>
    <div style='flex: 1'>Column 2</div>
</div>
<div class='grid'>
    <div>Item 1</div>
    <div>Item 2</div>
    <div>Item 3</div>
</div>";

var pdf = renderer.RenderHtmlAsPdf(html);
// All modern CSS features render correctly!
Dim renderer = New ChromePdfRenderer()

Dim html = "
<style>
    :root { --primary: #007bff; }
    .container { display: flex; gap: 20px; }
    .grid { display: grid; grid-template-columns: repeat(3, 1fr); }
</style>
<div class='container'>
    <div style='flex: 1; color: var(--primary)'>Column 1</div>
    <div style='flex: 1'>Column 2</div>
</div>
<div class='grid'>
    <div>Item 1</div>
    <div>Item 2</div>
    <div>Item 3</div>
</div>"

Dim pdf = renderer.RenderHtmlAsPdf(html)
' All modern CSS features render correctly!
$vbLabelText   $csharpLabel

基於HTML的水印

var pdf = renderer.RenderHtmlAsPdf(html);
pdf.ApplyWatermark(@"
    <div style='
        font-size: 48px;
        color: rgba(255, 0, 0, 0.5);
        transform: rotate(-45deg);
    '>DRAFT</div>");
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.ApplyWatermark(@"
    <div style='
        font-size: 48px;
        color: rgba(255, 0, 0, 0.5);
        transform: rotate(-45deg);
    '>DRAFT</div>");
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.ApplyWatermark("
    <div style='
        font-size: 48px;
        color: rgba(255, 0, 0, 0.5);
        transform: rotate(-45deg);
    '>DRAFT</div>")
$vbLabelText   $csharpLabel

遷移檢查表

遷移前

  • 盤點程式碼庫中的所有Spire.PDF使用情況
  • 測試現有PDF文字選擇性(關鍵問題檢測)
  • 文件LoadFromHTML()調用(這些是優先要修復的)
  • 獲取IronPDF授權金鑰來自ironpdf.com

程式碼更新

  • 移除Spire.PDF NuGet包(如果使用免費版本,還包括FreeSpire.PDF
  • 安裝IronPdf NuGet包
  • 更新命名空間導入(using Spire.Pdf;using IronPdf;
  • RenderHtmlAsPdf()(關鍵修復)
  • new PdfDocument() + PdfDocument.FromFile()
  • PdfDocument.Merge()
  • TextStamper + ApplyStamp()
  • SaveAs()
  • 移除所有Close()調用(在IronPDF中不需要)
  • 在應用程式啟動時新增授權初始化

測試

  • 驗證生成的PDF文字是否可選擇(關鍵測試)
  • 驗證CSS渲染改進(Flexbox/Grid現在可以運行)
  • 驗證檔案大小是否較小
  • 使用螢幕閱讀器測試可及性
  • 性能比較

請注意Spire是其相應所有者的註冊商標。 該站點與e-iceblue無關,未經其認可或贊助。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供參考,反映撰寫時公開可用的資訊。

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

除了開發,Curtis對物聯網(IoT)有濃厚的興趣,探索創新的方法來整合硬體和軟體。在空閒時間,他喜歡玩遊戲和建立Discord機器人,結合他對技術的熱愛與創造力。

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話