在企业应用、报表系统或财务工具的开发中,生成规范、专业的 PDF 文档是常见需求。与其在代码中硬编码布局,不如使用模板来提高开发效率。模板不仅能加快开发进程,还能确保品牌视觉与文档格式的一致性。
本文将介绍如何使用 Spire.PDF for .NET 在 C# 中通过 HTML 模板 或 预设 PDF 模板 生成 PDF 文档,无论是需要动态布局还是快速替换占位符,都能灵活应对。
本文目录
Spire.PDF for .NET 是什么
Spire.PDF for .NET 是一款功能强大的 PDF 操作库,允许 .NET 开发者无需依赖 Adobe Acrobat 即可创建、读取、编辑和转换 PDF 文档。该库提供全面的 API 接口,适用于生成报表、发票、证书及其他 PDF 格式文件,非常适合在 C# 应用中进行自动化文档处理。
与本教程相关的主要功能包括:
- HTML 转 PDF: 将网页或 HTML 字符串高保真地渲染为 PDF 文档。
- 文本替换: 在现有 PDF 中查找并替换文本,非常适合模板表单填充。
- 全面控制: 从文本、图像到安全性与批注,提供精细化控制能力。
在项目中配置 Spire.PDF
要在 C# 项目中通过模板生成 PDF,首先需将 Spire.PDF 引入项目中。对于 HTML 转 PDF 的场景,Spire.PDF 依赖外部渲染引擎(Qt WebEngine 或 Google Chrome)。本文以 Qt WebEngine为例。
步骤 1:安装 Spire.PDF
在 Visual Studio 的 NuGet 包管理器中运行以下命令:
Install-Package Spire.PDF
或从官方网站下载 Spire.PDF 安装包,并将 DLL 文件手动导入项目。
步骤 2:下载并配置 Qt 插件
根据系统下载对应的 Qt WebEngine 插件:
解压文件后可获得插件目录,例如:C:\plugins-windows-x64\plugins
在 C# 代码中注册插件路径:
HtmlConverter.PluginPath = @"C:\plugins-windows-x64\plugins";
在 C# 中通过 HTML 模板创建 PDF
HTML 模板非常适合需要表格、页眉页脚或复杂样式布局(如发票、报表)的文档。
步骤 1:构建带占位符的 HTML 模板
可在 HTML 中添加双花括号包裹的动态字段,例如:
<h1>发票</h1>
<p>发票编号: {{INVOICE_NUMBER}}</p>
<p>日期: {{INVOICE_DATE}}</p>
<p><strong>姓名: </strong> {{CUSTOMER_NAME}}</p>
步骤 2:使用运行时数据替换占位符
以下是一个生成发票 PDF 的完整示例代码:
using Spire.Additions.Qt;
using System.Drawing;
using Spire.Pdf.Graphics;
namespace CreatePdfFromHtmlTemplate
{
class Program
{
static void Main(string[] args)
{
// 带有占位符变量的HTML模板
string htmlTemplate = @"
<!DOCTYPE html>
<html lang=""zh"">
<head>
<meta charset=""UTF-8"">
<meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
<title>发票</title>
<style>
body {
font-family: ""SimHei"", ""黑体"", Tahoma, sans-serif;
margin: 40px auto;
padding: 20px;
max-width: 800px;
font-size: 20px;
}
h1 {
text-align: right;
font-size: 40px;
letter-spacing: 2px;
color: #222;
margin: 0 0 30px 0;
}
.invoice-header, .invoice-footer {
margin-bottom: 50px;
}
.invoice-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 3px solid #444;
padding-bottom: 10px;
}
.invoice-details {
margin: 20px 0;
padding: 15px;
background: #f5f5f5;
border-radius: 6px;
}
.invoice-details h2 {
font-size: 20px;
margin-bottom: 10px;
color: #444;
}
.info p {
margin: 2px 0;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th {
background-color: #efefef;
font-weight: 600;
}
tbody tr:nth-child(even) {
background: #f9f9f9;
}
.total {
margin-top: 20px;
text-align: right;
font-size: 15px;
}
.total p {
margin: 5px 0;
}
.total p span {
display: inline-block;
width: 120px;
}
.grand-total {
font-size: 18px;
font-weight: bold;
border-top: 2px solid #444;
margin-top: 10px;
padding-top: 10px;
}
.invoice-footer {
text-align: center;
font-size: 18px;
color: #666;
margin-top: 50px;
padding-top: 10px;
}
</style>
</head>
<body>
<div class=""invoice-header"">
<div>
<h2>公司名称</h2>
<p>123 商业街<br>重庆, 中国</p>
</div>
<div>
<h1>发票</h1>
<p>发票编号: {{INVOICE_NUMBER}}<br>日期: {{INVOICE_DATE}}</p>
</div>
</div>
<div class=""invoice-details"">
<h2>账单寄送至</h2>
<div class=""info"">
<p><strong>姓名:</strong> {{BILLER_NAME}}</p>
<p><strong>地址:</strong> {{BILLER_ADDRESS}}</p>
<p><strong>邮箱:</strong> {{BILLER_EMAIL}}</p>
</div>
</div>
<table>
<thead>
<tr>
<th>描述</th>
<th>数量</th>
<th>单价</th>
<th>行总计</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ITEM_DESCRIPTION}}</td>
<td>{{ITEM_QUANTITY}}</td>
<td>{{ITEM_UNIT_PRICE}}</td>
<td>{{ITEM_TOTAL}}</td>
</tr>
<!-- 这里可以添加更多行 -->
</tbody>
</table>
<div class=""total"">
<p><span>小计:</span> {{SUBTOTAL}}</p>
<p><span>税 ({{TAX_RATE}}%):</span> {{TAX}}</p>
<p class=""grand-total""><span>总计:</span> {{TOTAL}}</p>
</div>
<div class=""invoice-footer"">
<p>感谢您的惠顾!</p>
<p>如有任何疑问,请联系我们 该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。</p>
</div>
</body>
</html>
";
// 发票的样本数据 - 与模板占位符匹配的键值对
Dictionary<string, string> invoiceData = new Dictionary<string, string>()
{
{ "INVOICE_NUMBER", "12345" },
{ "INVOICE_DATE", "2025-08-25" },
{ "BILLER_NAME", "张三" },
{ "BILLER_ADDRESS", "重庆市新北街123号" },
{ "BILLER_EMAIL", "zhangsan@ example.com" },
{ "ITEM_DESCRIPTION", "咨询服务" },
{ "ITEM_QUANTITY", "10" },
{ "ITEM_UNIT_PRICE", "$100" },
{ "ITEM_TOTAL", "$1000" },
{ "SUBTOTAL", "$1000" },
{ "TAX_RATE", "5" },
{ "TAX", "$50" },
{ "TOTAL", "$1050" }
};
// 用实际数据值填充HTML模板
string populatedInvoice = PopulateInvoice(htmlTemplate, invoiceData);
// 指定生成的PDF输出文件路径
string outputFile = "HtmlToPdf.pdf";
// 指定HTML转换器的插件路径(QT插件)
string pluginPath = @"C:\plugins-windows-x64\plugins";
// 设置HTML到PDF转换所需的插件路径
HtmlConverter.PluginPath = pluginPath;
// 使用指定设置将HTML字符串转换为PDF
HtmlConverter.Convert(
populatedInvoice,
outputFile,
true, // 启用JavaScript
100000, // 超时(毫秒)
new SizeF(595, 842), // A4纸大小(595x842点)
new PdfMargins(20), // 四周20点边距
LoadHtmlType.SourceCode // 从源代码字符串加载HTML
);
}
// 辅助方法: 用数据字典中的实际值替换模板占位符
private static string PopulateInvoice(string template, Dictionary<string, string> data)
{
string result = template;
foreach (var entry in data)
{
result = result.Replace("{{" + entry.Key + "}}", entry.Value);
}
return result;
}
}
}
实现原理
- 在 HTML 模板中定义形如 {{VARIABLE_NAME}} 的占位符。
- 使用字典存储实际数据的键值对,与模板占位符对应。
- 程序运行时将模板中的占位符替换为真实数据。
- 调用 Spire.PDF(配合 Qt 插件)将 HTML 渲染为 PDF 文件。
输出结果:
在 C# 中通过 PDF 模板生成 PDF
有时设计团队会提供带有占位符(如 {PROJECT_NAME})的静态 PDF 模板。通过简单的文本替换即可将这些模板快速填充成正式文档。
示例:填充项目报告模板
using Spire.Pdf;
using Spire.Pdf.Texts;
using static Spire.Pdf.Texts.PdfTextReplaceOptions;
namespace GeneratePdfFromPdfTemplate
{
class Program
{
static void Main(string[] args)
{
// 创建一个PdfDocument对象
PdfDocument doc = new PdfDocument();
// 加载一个PDF文件
doc.LoadFromFile(@"C:\Users\Administrator\Desktop\Template.pdf");
// 创建一个PdfTextReplaceOptions对象并指定选项
PdfTextReplaceOptions textReplaceOptions = new PdfTextReplaceOptions();
textReplaceOptions.ReplaceType = ReplaceActionType.WholeWord; // 替换类型设置为整词替换
// 获取特定页面
PdfPageBase page = doc.Pages[0];
// 基于页面创建一个PdfTextReplacer对象
PdfTextReplacer textReplacer = new PdfTextReplacer(page);
textReplacer.Options = textReplaceOptions;
// 旧字符串和新字符串的字典
Dictionary<string, string> replacements = new Dictionary<string, string>()
{
{ "{PROJECT_NAME}", "新网站开发" },
{ "{PROJECT_NO}", "2023-001" },
{ "{PROJECT MANAGER}", "爱丽丝·约翰逊" },
{ "{PERIOD}", "2023年第三季度" },
{ "{START_DATE}", "2023年7月1日" },
{ "{END_DATE}", "2023年9月30日" }
};
// 遍历字典进行文本替换
foreach (var pair in replacements)
{
textReplacer.ReplaceText(pair.Key, pair.Value);
}
// 将文档保存为另一个PDF文件
doc.SaveToFile("FromPdfTemplate.pdf");
doc.Close();
}
}
}
实现原理
- 加载包含占位符的现有 PDF 文件。
- 使用字典存储占位符与实际数据的映射关系。
- 遍历字典并替换 PDF 中对应的文本。
- 将修改后的文档另存为新 PDF 文件。
限制说明: 此方法仅适用于短文本(如姓名、编号、日期等)的替换。对于多行文本或动态扩展的内容,它的效果不佳,因为PDF不会自动重新排版文本。对于较大的内容块,请使用HTML或Word模板。
输出结果:
Spire.PDF 支持更多文本替换设置,请参考:在 C# 中替换 PDF 文档中的文本
根据模板生成 PDF 最佳实践
选择合适的模板类型
- HTML 模板: 适用于需要复杂样式、表格或长文本的文档,灵活性最高。
- PDF 模板: 适用于布局固定、仅需替换少量字段的文档(如表单、报告)。
- Word 模板: 若文档源于 .docx 文件,可使用 Spire.Doc for .NET 进行占位符替换并导出为 PDF。
占位符设计
- 使用独特且清晰的占位符格式(如 {NAME}、{DATE})避免误替换。
- 保持一致的命名规范,减少维护错误。
测试与验证
- 使用真实或代表性数据进行测试,检查文本对齐、换行与版面效果。
模板管理
- 将模板文件与代码分离,方便设计人员独立维护。
- 建立模板规范文档,定义命名、语法和样式要求。
常见问题解答
Q1:可以使用 Google Chrome 代替 Qt WebEngine 渲染 HTML 吗?
可以。对于复杂 HTML、CSS 或现代 JavaScript,建议使用 ChromeHtmlConverter 类,它能生成更精确的 PDF。
?详见教程:使用 ChromeHtmlConverter 将 HTML 转换为 PDF
Q2:在 PDF 模板中替换文本有哪些限制?
PDF 布局固定,替换文本不会自动重排。当新文本过长可能溢出,过短则留白。适用于可预测的字段内容(如姓名、日期等)。对于多行文本或动态内容,可使用 HTML 或 Word 模板,或借助 Spire.PDF 的绘图 API 直接绘制新文本块。
Q3:能否通过 Spire.PDF 从 Word 模板生成 PDF?
Spire.PDF 主要用于 PDF 操作,如需根据 Word 模板生成PDF,可使用 Spire.Doc for .NET 替换 Word 模板内容,然后再保存为 PDF。
Q4:如何在模板生成的 PDF 中插入图片、Logo 或签名?
- 在 PDF 中,可通过 PdfCanvas.drawImage() 方法绘制图片。
- 在 HTML 模板中,可直接使用
标签。
这样即可轻松添加公司 Logo、水印或电子签名。
结论
使用 Spire.PDF 在 C# 中基于模板生成 PDF,是提升文档自动化效率的理想方式。无论选择 HTML 模板还是现有 PDF 模板,开发者都能轻松创建内容准确、版面统一、外观专业的文件。通过在开发流程中引入模板机制,不仅能显著减少重复性工作,还能确保品牌风格与格式的一致性。
在实施过程中,合理选择模板类型、规范占位符设计,并在部署前充分测试真实数据,能够帮助你获得更稳定的输出效果。随着项目的深入,还可以结合 Spire.PDF 的高级功能,如数字签名、加密与批注等,实现更安全、更智能的文档处理方案。
通过这一方法,你的团队将能够在保证质量与一致性的同时,大幅提升 PDF 文档的生成速度与管理效率,从而让自动化办公与报告生成更加高效、可控。
申请临时 License
如果您需要去除生成文档中的评估提示或解除功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。