如何在Chrome中调试HTML以创建像素完美的PDF
从iText迁移到IronPDF,将您的.NET PDF工作流程从程序化API(在代码中构建Cell对象)转换为具有CSS3和JavaScript支持的HTML优先方法。 本指南提供了一步步的迁移路径,消除了AGPL暴露和对单独pdfHTML插件的需求。
为什么要从 iText 迁移到 IronPDF.
AGPL许可证考虑因素
iText(由iText Group / Apryse Group NV所有)具有商业团队应预先权衡的许可证特性:
-
AGPL病毒许可证:如果您在网络应用程序中使用iText的开源许可证,通常解释为需要您向通过网络与其交互的任何人发布应用程序的源代码。 对于闭源的商业软件,这通常意味着购买商业许可证。
-
仅订阅的商业授权:iText的商业许可证作为基于PDF处理量的年度订阅销售; 永续选项没有在公共价格页面上宣传(仅提供定制OEM条款报价)。
-
pdfHTML附加组件成本: HTML到PDF转换需要
itext包(当前为9.6.0)之上。 -
复杂的许可证审计:企业部署面临许可证复杂性和审计风险。
-
程序化优先API: 核心iText通过在代码中组合
Cell对象来构建PDF; pdfHTML让您从HTML开始。 - 定义的CSS子集,没有渲染时JS:pdfHTML支持已定义的CSS子集,并在将HTML转换为PDF时不执行JavaScript(PDF级JS表单操作是一个单独的受支持功能)。
iText 与IronPDF对比
| 特征 | iText 9 / iTextSharp 5.x | IronPDF |
|---|---|---|
| 许可证 | AGPL(病毒)或商业年度订阅 | 商业、永久选项 |
| HTML 转 PDF | 单独的itext.pdfhtml附加组件(6.3.2) |
内置 Chromium 渲染器 |
| CSS 支持 | pdfHTML中的定义CSS子集 | 完全 CSS3、Flexbox、网格 |
| 渲染时的JavaScript | pdfHTML在HTML转换为PDF时不运行JS | 完整的JS在渲染时执行 |
| 应用程序接口范例 | 程式化(段落、表格、单元格) | HTML 优先,带 CSS |
| 学习曲线 | 陡峭(PDF 坐标系) | 对网络开发人员友好 |
| 开源风险 | 必须是 AGPL 下的开源网络应用程序 | 无病毒要求 |
| 定价模式 | 年度订阅(基于卷)或定制OEM | 永久或订阅 |
对于在现代.NET上规范化的团队,IronPDF的HTML优先策略依赖于团队已经具备的Web开发技能。
迁移复杂性评估
按功能估算的工作量
| 特征 | 迁移复杂性 |
|---|---|
| HTML 至 PDF | 极低 |
| 合并 PDF | low |
| 文本和图片 | low |
| 表格 | 语言 |
| 页眉/页脚 | 语言 |
| 安全/加密 | low |
范式转换
iText此次迁移的根本转变是从程序化PDF构建转向HTML优先渲染:
iText: PdfWriter → PdfDocument → Document → Add(Paragraph) → Add(Table)
IronPDF: ChromePdfRenderer → RenderHtmlAsPdf(htmlString) → SaveAs()
这种模式的转变是一种解放:您无需学习 iText 的对象模型,而是使用网络开发人员已经掌握的 HTML 和 CSS 技能。
开始之前
前提条件
- .NET 环境: .NET Framework 4.6.2+ 或 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 访问权限:能够安装 NuGet 包
- IronPDF 许可证:请从ironpdf.com获取您的许可证密钥。
NuGet 软件包变更
# Remove iText packages (current naming is 'itext'; 'itext7' is the deprecated alias)
dotnet remove package itext
dotnet remove package itext.pdfhtml
dotnet remove package itext7
dotnet remove package itext7.pdfhtml
dotnet remove package itextsharp
# Install IronPDF
dotnet add package IronPdf
# Remove iText packages (current naming is 'itext'; 'itext7' is the deprecated alias)
dotnet remove package itext
dotnet remove package itext.pdfhtml
dotnet remove package itext7
dotnet remove package itext7.pdfhtml
dotnet remove package itextsharp
# Install IronPDF
dotnet add package IronPdf
许可配置
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup (Program.vb or Startup.vb)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
确定 iText 的用法
# Find all iText references
grep -r "using iText\|using iTextSharp" --include="*.cs" .
grep -r "PdfWriter\|PdfDocument\|Document\|Paragraph\|Table\|Cell" --include="*.cs" .
grep -r "HtmlConverter\|ConverterProperties" --include="*.cs" .
# Find all iText references
grep -r "using iText\|using iTextSharp" --include="*.cs" .
grep -r "PdfWriter\|PdfDocument\|Document\|Paragraph\|Table\|Cell" --include="*.cs" .
grep -r "HtmlConverter\|ConverterProperties" --include="*.cs" .
完整的 API 参考
类映射
| iText 7+类 | iTextSharp 5.x类 | IronPDF 同等产品 |
|---|---|---|
PdfWriter |
PdfWriter |
ChromePdfRenderer |
PdfDocument |
Document |
PdfDocument |
Document |
Document |
ChromePdfRenderer.RenderHtmlAsPdf() |
Paragraph |
Paragraph |
HTML <p>, <h1>等 |
Table |
PdfPTable |
HTML <table> |
Cell |
PdfPCell |
HTML <td>, <th> |
Image |
Image |
HTML <img> |
PdfReader |
PdfReader |
PdfDocument.FromFile() |
PdfMerger |
不适用 | PdfDocument.Merge() |
命名空间映射
| iText命名空间 | IronPDF 同等产品 |
|---|---|
iText.Kernel.Pdf |
IronPdf |
iText.Layout |
IronPdf |
iText.Layout.Element |
使用 HTML 元素 |
iText.Html2pdf |
IronPdf(内置) |
iText.IO.Image |
使用HTML <img> |
iText.Kernel.Utils |
IronPdf |
代码迁移示例
示例 1:HTML 到 PDF 的转换
之前(iText):
// NuGet: Install-Package itext7
using iText.Html2pdf;
using System.IO;
class Program
{
static void Main()
{
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
string outputPath = "output.pdf";
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
HtmlConverter.ConvertToPdf(html, fs);
}
}
}
// NuGet: Install-Package itext7
using iText.Html2pdf;
using System.IO;
class Program
{
static void Main()
{
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
string outputPath = "output.pdf";
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
HtmlConverter.ConvertToPdf(html, fs);
}
}
}
Imports iText.Html2pdf
Imports System.IO
Class Program
Shared Sub Main()
Dim html As String = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
Dim outputPath As String = "output.pdf"
Using fs As FileStream = New FileStream(outputPath, FileMode.Create)
HtmlConverter.ConvertToPdf(html, fs)
End Using
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class
iText的方法需要单独的itext 9.6.0之上),创建一个using语句包装所有内容以便正确处理。 HtmlConverter.ConvertToPdf() 方法直接写入流。
IronPDF的方法更简洁:创建一个SaveAs()。 没有单独的软件包,没有流管理,Chromium 渲染引擎提供卓越的 CSS3 和 JavaScript 支持。 有关其他渲染选项,请参阅 HTML to PDF 文档。
示例 2:合并多个 PDF 文件
之前(iText):
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Kernel.Utils;
using System.IO;
class Program
{
static void Main()
{
string outputPath = "merged.pdf";
string[] inputFiles = { "document1.pdf", "document2.pdf", "document3.pdf" };
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdfDoc = new PdfDocument(writer))
{
PdfMerger merger = new PdfMerger(pdfDoc);
foreach (string file in inputFiles)
{
using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
{
merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
}
}
}
}
}
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Kernel.Utils;
using System.IO;
class Program
{
static void Main()
{
string outputPath = "merged.pdf";
string[] inputFiles = { "document1.pdf", "document2.pdf", "document3.pdf" };
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdfDoc = new PdfDocument(writer))
{
PdfMerger merger = new PdfMerger(pdfDoc);
foreach (string file in inputFiles)
{
using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
{
merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
}
}
}
}
}
Imports iText.Kernel.Pdf
Imports iText.Kernel.Utils
Imports System.IO
Class Program
Shared Sub Main()
Dim outputPath As String = "merged.pdf"
Dim inputFiles As String() = {"document1.pdf", "document2.pdf", "document3.pdf"}
Using writer As New PdfWriter(outputPath)
Using pdfDoc As New PdfDocument(writer)
Dim merger As New PdfMerger(pdfDoc)
For Each file As String In inputFiles
Using sourcePdf As New PdfDocument(New PdfReader(file))
merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages())
End Using
Next
End Using
End Using
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdfDocuments = new List<PdfDocument>
{
PdfDocument.FromFile("document1.pdf"),
PdfDocument.FromFile("document2.pdf"),
PdfDocument.FromFile("document3.pdf")
};
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdfDocuments = new List<PdfDocument>
{
PdfDocument.FromFile("document1.pdf"),
PdfDocument.FromFile("document2.pdf"),
PdfDocument.FromFile("document3.pdf")
};
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
}
}
Imports IronPdf
Imports System.Collections.Generic
Class Program
Shared Sub Main()
Dim pdfDocuments As New List(Of PdfDocument) From {
PdfDocument.FromFile("document1.pdf"),
PdfDocument.FromFile("document2.pdf"),
PdfDocument.FromFile("document3.pdf")
}
Dim merged = PdfDocument.Merge(pdfDocuments)
merged.SaveAs("merged.pdf")
End Sub
End Class
iText的合并操作需要大量样板代码:为输出创建一个PdfReader的源文件。 您还必须使用merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages())指定页面范围。
IronPDF将其简化为三个步骤:使用PdfDocument.Merge()方法,然后保存。 使整个合并操作具有可读性和可维护性。 了解有关 合并和拆分 PDF 的更多信息。
示例 3:使用文本和图像创建 PDF.
之前(iText):
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.IO.Image;
class Program
{
static void Main()
{
string outputPath = "document.pdf";
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdf = new PdfDocument(writer))
using (Document document = new Document(pdf))
{
document.Add(new Paragraph("Sample PDF Document"));
document.Add(new Paragraph("This document contains text and an image."));
Image img = new Image(ImageDataFactory.Create("image.jpg"));
img.SetWidth(200);
document.Add(img);
}
}
}
// NuGet: Install-Package itext7
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.IO.Image;
class Program
{
static void Main()
{
string outputPath = "document.pdf";
using (PdfWriter writer = new PdfWriter(outputPath))
using (PdfDocument pdf = new PdfDocument(writer))
using (Document document = new Document(pdf))
{
document.Add(new Paragraph("Sample PDF Document"));
document.Add(new Paragraph("This document contains text and an image."));
Image img = new Image(ImageDataFactory.Create("image.jpg"));
img.SetWidth(200);
document.Add(img);
}
}
}
Imports iText.Kernel.Pdf
Imports iText.Layout
Imports iText.Layout.Element
Imports iText.IO.Image
Class Program
Shared Sub Main()
Dim outputPath As String = "document.pdf"
Using writer As New PdfWriter(outputPath),
pdf As New PdfDocument(writer),
document As New Document(pdf)
document.Add(New Paragraph("Sample PDF Document"))
document.Add(New Paragraph("This document contains text and an image."))
Dim img As New Image(ImageDataFactory.Create("image.jpg"))
img.SetWidth(200)
document.Add(img)
End Using
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = @"
<h1>Sample PDF Document</h1>
<p>This document contains text and an image.</p>
<img src='image.jpg' width='200' />";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("document.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = @"
<h1>Sample PDF Document</h1>
<p>This document contains text and an image.</p>
<img src='image.jpg' width='200' />";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("document.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "
<h1>Sample PDF Document</h1>
<p>This document contains text and an image.</p>
<img src='image.jpg' width='200' />"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("document.pdf")
End Sub
End Class
这个例子最清楚地说明了范式的转变。 iText 要求
- 三重嵌套
PdfWriter,PdfDocument,Document) - 为每个文本元素使用
Paragraph对象 - 使用
ImageDataFactory.Create()加载图像 - 创建一个
SetWidth() - 为每个元素调用
document.Add()
IronPDF使用标准HTML:width属性。 网络开发人员可以立即利用他们现有的技能,而设计人员则可以使用他们已经掌握的 CSS 对文档进行样式设计。
关键迁移说明
范式转变:编程到 HTML 优先
这次 iText 迁移中最重要的变化是概念上的。 iText 以编程方式生成 PDF:
// iText approach
document.Add(new Paragraph("Title")
.SetTextAlignment(TextAlignment.CENTER)
.SetFontSize(24)
.SetBold());
var table = new Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth();
table.AddHeaderCell(new Cell().Add(new Paragraph("ID")));
table.AddHeaderCell(new Cell().Add(new Paragraph("Name")));
// ... many more lines
// iText approach
document.Add(new Paragraph("Title")
.SetTextAlignment(TextAlignment.CENTER)
.SetFontSize(24)
.SetBold());
var table = new Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth();
table.AddHeaderCell(new Cell().Add(new Paragraph("ID")));
table.AddHeaderCell(new Cell().Add(new Paragraph("Name")));
// ... many more lines
' iText approach
document.Add(New Paragraph("Title") _
.SetTextAlignment(TextAlignment.CENTER) _
.SetFontSize(24) _
.SetBold())
Dim table = New Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth()
table.AddHeaderCell(New Cell().Add(New Paragraph("ID")))
table.AddHeaderCell(New Cell().Add(New Paragraph("Name")))
' ... many more lines
IronPDF 使用 HTML 和 CSS:
//IronPDFapproach
string html = @"
<style>
h1 { text-align: center; font-size: 24px; font-weight: bold; }
table { width: 100%; border-collapse: collapse; }
th { background-color: #4CAF50; color: white; padding: 8px; }
</style>
<h1>Title</h1>
<table>
<tr><th>ID</th><th>Name</th></tr>
</table>";
var pdf = renderer.RenderHtmlAsPdf(html);
//IronPDFapproach
string html = @"
<style>
h1 { text-align: center; font-size: 24px; font-weight: bold; }
table { width: 100%; border-collapse: collapse; }
th { background-color: #4CAF50; color: white; padding: 8px; }
</style>
<h1>Title</h1>
<table>
<tr><th>ID</th><th>Name</th></tr>
</table>";
var pdf = renderer.RenderHtmlAsPdf(html);
'IronPDFapproach
Dim html As String = "
<style>
h1 { text-align: center; font-size: 24px; font-weight: bold; }
table { width: 100%; border-collapse: collapse; }
th { background-color: #4CAF50; color: white; padding: 8px; }
</style>
<h1>Title</h1>
<table>
<tr><th>ID</th><th>Name</th></tr>
</table>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
AGPL暴露已移除
根据iText的AGPL条款,使用iText的Web应用程序通常预期将其源代码释放给通过网络与其交互的任何人; 商业许可证是替代路径。IronPDF的商业许可证允许在专有软件中部署,而无需病毒许可要求。
无需 pdfHTML 附加组件
iText需要单独的itext包上。 IronPDF在基本包中包括了基于Chromium的HTML渲染。
方法替换模式
| iText 模式 | IronPDF 替代品 |
|---|---|
SetTextAlignment(TextAlignment.CENTER) |
CSS text-align: center |
SetFontSize(24) |
CSS font-size: 24px |
SetBold() |
CSS font-weight: bold |
new Table(3) |
HTML <table> |
AddHeaderCell(new Cell().Add(new Paragraph())) |
HTML <th> |
AddCell(new Cell().Add(new Paragraph())) |
HTML <td> |
故障排除
问题 1:PdfWriter/文档模式
问题: 代码使用PdfWriter → PdfDocument → Document嵌套模式。
解决方案: 用ChromePdfRenderer替换:
// Delete this iText pattern:
// using (var writer = new PdfWriter(outputPath))
// using (var pdfDoc = new PdfDocument(writer))
// using (var document = new Document(pdfDoc))
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
// Delete this iText pattern:
// using (var writer = new PdfWriter(outputPath))
// using (var pdfDoc = new PdfDocument(writer))
// using (var document = new Document(pdfDoc))
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs(outputPath)
问题 2:HtmlConverter 未找到
问题: 代码使用itext.pdfhtml附加组件中。
解决方案:使用IronPDF内置的 HTML 渲染功能:
// iText (requires pdfHTML add-on)
HtmlConverter.ConvertToPdf(html, fileStream);
//IronPDF(built-in)
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
// iText (requires pdfHTML add-on)
HtmlConverter.ConvertToPdf(html, fileStream);
//IronPDF(built-in)
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
' iText (requires pdfHTML add-on)
HtmlConverter.ConvertToPdf(html, fileStream)
' IronPDF(built-in)
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs(outputPath)
问题 3:PdfMerger 的复杂性
问题: iText的PdfMerger需要嵌套的读取器和页面范围指定。
解决方案:使用IronPDF的静态合并方法:
// iText merger pattern (delete this)
// using (PdfDocument pdfDoc = new PdfDocument(writer))
// {
// PdfMerger merger = new PdfMerger(pdfDoc);
// foreach (string file in inputFiles)
// {
// using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
// {
// merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
// }
// }
// }
//IronPDF(simple)
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
// iText merger pattern (delete this)
// using (PdfDocument pdfDoc = new PdfDocument(writer))
// {
// PdfMerger merger = new PdfMerger(pdfDoc);
// foreach (string file in inputFiles)
// {
// using (PdfDocument sourcePdf = new PdfDocument(new PdfReader(file)))
// {
// merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages());
// }
// }
// }
//IronPDF(simple)
var merged = PdfDocument.Merge(pdfDocuments);
merged.SaveAs("merged.pdf");
Imports System.Collections.Generic
' iText merger pattern (delete this)
' Using pdfDoc As New PdfDocument(writer)
' Dim merger As New PdfMerger(pdfDoc)
' For Each file As String In inputFiles
' Using sourcePdf As New PdfDocument(New PdfReader(file))
' merger.Merge(sourcePdf, 1, sourcePdf.GetNumberOfPages())
' End Using
' Next
' End Using
' IronPDF(simple)
Dim merged = PdfDocument.Merge(pdfDocuments)
merged.SaveAs("merged.pdf")
迁移清单
迁移前
- 清点代码库中所有 iText API 调用
- 识别程序化 PDF 构建模式(段落、表格、单元格)
- 文档 HtmlConverter 用法(pdfHTML 插件)
- 评估AGPL合规风险
- 获取IronPDF许可证密钥
代码迁移
- 移除iText NuGet包:
itext.pdfhtml/iTextSharp) - 安装IronPDF NuGet包:
dotnet add package IronPdf - 更新命名空间导入(
using iText.*→using IronPdf) - 将
ChromePdfRenderer - 转换
Cell为HTML元素 - 用
HtmlConverter.ConvertToPdf() - 更新合并操作为
PdfDocument.Merge() - 添加启动时许可证密钥初始化功能
测试
- 测试所有 PDF 生成路径
- 验证视觉输出是否符合预期
- 使用复杂的 HTML/CSS 内容进行测试
- 基准性能
后迁移
- 删除 iText 许可证文件和引用
- 更新文档
- 取消 iText 订阅(如适用)
- 归档旧版 iText 代码

