如何用 C# 从 Spire.PDF 迁移到 IronPDF
从 Spire.PDF 迁移到IronPDF可将您的 PDF 生成工作流程从将文本渲染为图像的库转变为使用现代 Chromium 渲染引擎生成真实、可选择、可搜索文本的库。本指南提供了完整的分步迁移路径,可解决 Spire.PDF 关键的 HTML 渲染限制和字体嵌入问题。
为什么要从 Spire.PDF 迁移到 IronPDF.
了解 Spire.PDF.
Spire.PDF 是一个功能强大的商用 PDF 库,专为 .NET 开发人员高效处理 PDF 文档而设计。 Spire.PDF 因其特殊功能(尤其是在传统应用程序中)而在编程界声名鹊起,其集成功能可与 E-iceblue 工具集中的其他组件无缝对接。
然而,Spire.PDF 存在几个影响实际使用的基本问题,特别是 HTML 到 PDF 的转换和对现代网络标准的支持。
关键技术问题
| 问题 | 影响 | IronPDF 解决方案 |
|---|---|---|
| 以图像形式呈现的文本 | PDF 无法搜索、无法访问、无法复制文本 | 真实文本渲染 |
| Internet Explorer 依赖性 | 过时的渲染、安全风险 | 现代 Chromium 引擎 |
| 字体嵌入失败 | 文件在其他系统上看起来不对 | 可靠的字体处理 |
| 大量部署足迹 | 内存使用率高,启动速度慢 | 高效部署 |
| 有限的 CSS 支持 | 现代布局无法正确呈现 | 完全支持 CSS3 |
核心问题:基于图像的 PDF 文件
Spire.PDF 的一个明显缺点是倾向于将 HTML 文档中的文本呈现为图像。 这将导致 PDF 文本无法选择或搜索,对于需要搜索功能或文档文本交互的应用程序来说,这可能是一个严重的限制。
当您使用 Spire.PDF 的 LoadFromHTML() 方法时,它通常会将文本渲染为位图图像而不是实际文本,从而导致以下问题:
- 文本不能选择
- 不能搜索文本
- 文本不得复制
- 屏幕阅读器无法阅读(违反可访问性原则)
- 文件较大
- 缩放导致像素化
Spire.PDF 与IronPDF对比
| 特征 | Spire.PDF | IronPDF |
|---|---|---|
| HTML 到 PDF 渲染 | 文本呈现为图像 | 真正的文本渲染(可选择、可搜索) |
| 渲染引擎 | 某些系统依赖于 Internet Explorer | 基于 Chromium,符合现代网络标准 |
| 字体处理 | 字体嵌入的已知问题 | 可靠、稳健的字体处理 |
| CSS3 支持。 | 有限的 | 满的 |
| Flexbox/网格 | 不支持 | 支持 |
| JavaScript语言 | 有限的 | 完整的 ES6+ |
| PDF 辅助功能 | 差(基于图像) | 出色的 |
| API 设计 | 复杂 | 简单直观 |
| 部署足迹 | 大型项目 | 缓和 |
| 许可 | 免费/商业 | 商业翻译 |
对于计划在 2025 年和 2026 年之前采用 .NET 10 和 C# 14 的团队,IronPDF 通过将文本呈现为实际可选择的文本而不是图像,解决了 Spire.PDF 的 HTML 到 PDF 转换中的关键问题,确保了 PDF 的可搜索性和可访问性。
开始之前
前提条件
- .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 访问权限:能够安装 NuGet 包
- 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
许可配置
// 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: 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
核心 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
After (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
本例展示了 HTML 渲染的根本区别。 Spire.PDF 使用 LoadFromHTML() 和 PdfHtmlLayoutFormat 对象,该对象通常将文本渲染为位图图像。 结果是用户无法选择、复制或搜索文本的 PDF 文件。
IronPDF 使用 ChromePdfRenderer 和 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
After (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
Spire.PDF 需要手动加载每个文档,使用 new PdfDocument() + LoadFromFile(),然后使用 InsertPageRange() 指定要插入的页面,最后对每个文档调用 Close()。
IronPDF 使用更简单的 PdfDocument.FromFile() 模式和接受多个文档的静态 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
After (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
Spire.PDF 使用基于画布的绘图模型,通过 PdfFont、PdfBrush 和 page.Canvas.DrawString() 来定位文本,使用 PointF 将其放置在特定坐标上。
IronPDF 使用 TextStamper 对象,该对象具有 Text、FontSize、VerticalOffset 和 HorizontalOffset 等直观属性,然后使用 ApplyStamp() 应用它。 这种方法更具声明性,更易于维护。
文本即图像问题
为什么这一点至关重要
当 Spire.PDF 使用基于图像的渲染技术将 HTML 转换为 PDF 时,您的文档将失去基本功能:
1. 不支持文本搜索:用户无法使用 Ctrl+F 查找文本。 文档管理系统无法对内容进行索引。
2. 无法选择/复制文本:尝试复制引文、参考文献或数据的用户无法选择文本——它显示的是图像。
3. 无障碍访问违规:基于图像的 PDF 不符合 WCAG 2.1 标准、第 508 条(美国政府)标准、ADA 要求和屏幕阅读器兼容性要求。
4. 文件大小较大:相同内容的比较显示,Spire.PDF(基于图像)生成的文件比 IronPDF(基于文本)大 16 倍。
检测:您的 PDF 是否基于图像?
打开 Spire.PDF 生成的文档并尝试这些测试:
1.文本选择:点击并拖动选择文本。 如果没有什么亮点 → 基于图像
- Ctrl+F 搜索:搜索页面上的任何单词。 如果 "未找到匹配内容",请选择 "基于图像"。 3.复制/粘贴:选择文本并复制到记事本。 如果没有粘贴 → 基于图像
Internet Explorer 问题
Spire.PDF 的渲染引擎
在某些环境中,Spire.PDF 的 HTML 渲染依赖于 Internet Explorer/Edge Legacy。 IE 已于 2022 年废弃,现代 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>
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
现代 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!
基于 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>")
迁移清单
迁移前
- 清点代码库中所有 Spire.PDF 的使用情况
- 测试现有PDF文件的文本选择性(关键问题检测)
- 文档
LoadFromHTML()调用(这些是优先修复的问题) - 从ironpdf.com获取IronPDF许可证密钥
代码更新
- 移除
Spire.PDFNuGet 包(如果使用免费版本,则移除FreeSpire.PDF) - 安装
IronPdfNuGet 包 - 更新命名空间导入(
using Spire.Pdf;→using IronPdf;) - 将
LoadFromHTML()替换为RenderHtmlAsPdf()(关键修复) - 将
new PdfDocument()+LoadFromFile()替换为PdfDocument.FromFile() - 将
InsertPageRange()替换为PdfDocument.Merge() - 将
Canvas.DrawString()替换为TextStamper+ApplyStamp() - 将
SaveToFile()替换为SaveAs() - 删除所有
Close()调用(IronPDF 中不需要) - 在应用程序启动时添加许可证初始化
测试
- 验证生成的 PDF 文件中的文本是否可选(关键测试)
- 验证 CSS 渲染改进(Flexbox/Grid 现在可以正常工作)
- 确认文件大小较小
- 使用屏幕阅读器测试辅助功能
- 性能比较

