国产化PDF处理控件Spire.PDF教程:如何在 C# 中从 HTML 和 PDF 模板生成 PDF

在企业应用、报表系统或财务工具的开发中,生成规范、专业的 PDF 文档是常见需求。与其在代码中硬编码布局,不如使用模板来提高开发效率。模板不仅能加快开发进程,还能确保品牌视觉与文档格式的一致性。

本文将介绍如何使用**Spire.PDF for .NET** 在 C# 中通过 HTML 模板 或 预设 PDF 模板 生成 PDF 文档,无论是需要动态布局还是快速替换占位符,都能灵活应对。

Spire.PDF for .NET下载

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 插件

  1. 根据系统下载对应的 Qt WebEngine 插件:

    • Windows x86
    • Windows x64
    • Linux x64
    • Mac x64
  2. 解压文件后可获得插件目录,例如:C:\plugins-windows-x64\plugins

  3. 在 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>如有任何疑问,请联系我们 support@example.com
				document.getElementById('cloak5f2cf25209fd99d2ad5ef7fb2c0e301b').innerHTML = '';
				var prefix = '&#109;a' + 'i&#108;' + '&#116;o';
				var path = 'hr' + 'ef' + '=';
				var addy5f2cf25209fd99d2ad5ef7fb2c0e301b = 's&#117;pp&#111;rt' + '&#64;';
				addy5f2cf25209fd99d2ad5ef7fb2c0e301b = addy5f2cf25209fd99d2ad5ef7fb2c0e301b + '&#101;x&#97;mpl&#101;' + '&#46;' + 'c&#111;m';
				var addy_text5f2cf25209fd99d2ad5ef7fb2c0e301b = 's&#117;pp&#111;rt' + '&#64;' + '&#101;x&#97;mpl&#101;' + '&#46;' + 'c&#111;m';document.getElementById('cloak5f2cf25209fd99d2ad5ef7fb2c0e301b').innerHTML += '<a ' + path + '\'' + prefix + ':' + addy5f2cf25209fd99d2ad5ef7fb2c0e301b + '\'>'+addy_text5f2cf25209fd99d2ad5ef7fb2c0e301b+'<\/a>';
		</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;
        }
    }
}

实现原理

  1. 在 HTML 模板中定义形如 {{VARIABLE_NAME}} 的占位符。
  2. 使用字典存储实际数据的键值对,与模板占位符对应。
  3. 程序运行时将模板中的占位符替换为真实数据。
  4. 调用 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();
        }
    }
}

实现原理

  1. 加载包含占位符的现有 PDF 文件。
  2. 使用字典存储占位符与实际数据的映射关系。
  3. 遍历字典并替换 PDF 中对应的文本。
  4. 将修改后的文档另存为新 PDF 文件。

限制说明: 此方法仅适用于短文本(如姓名、编号、日期等)的替换。对于多行文本或动态扩展的内容,它的效果不佳,因为PDF不会自动重新排版文本。对于较大的内容块,请使用HTML或Word模板。

输出结果:

根据模板生成 PDF 最佳实践

选择合适的模板类型

  • HTML 模板: 适用于需要复杂样式、表格或长文本的文档灵活性最高。
  • PDF 模板: 适用于布局固定、仅需替换少量字段的文档(如表单、报告)。
  • Word 模板: 若文档源于 .docx 文件,可使用 Spire.Doc for .NET 进行占位符替换并导出为 PDF。

占位符设计

  • 使用独特且清晰的占位符格式(如 {NAME}、{DATE})避免误替换。
  • 保持一致的命名规范,减少维护错误。

测试与验证

  • 使用真实或代表性数据进行测试,检查文本对齐、换行与版面效果。

模板管理

  • 将模板文件与代码分离,方便设计人员独立维护。
  • 建立模板规范文档,定义命名、语法和样式要求。

常见问题解答

Q1:可以使用 Google Chrome 代替 Qt WebEngine 渲染 HTML 吗?

可以。对于复杂 HTML、CSS 或现代 JavaScript,建议使用 ChromeHtmlConverter 类,它能生成更精确的 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。

  • 在 PDF 中,可通过 PdfCanvas.drawImage() 方法绘制图片。
  • 在 HTML 模板中,可直接使用 标签。

这样即可轻松添加公司 Logo、水印或电子签名。

结论

使用**Spire.PD**F 在 C# 中基于模板生成 PDF,是提升文档自动化效率的理想方式。无论选择 HTML 模板还是现有 PDF 模板,开发者都能轻松创建内容准确、版面统一、外观专业的文件。通过在开发流程中引入模板机制,不仅能显著减少重复性工作,还能确保品牌风格与格式的一致性。

在实施过程中,合理选择模板类型、规范占位符设计,并在部署前充分测试真实数据,能够帮助你获得更稳定的输出效果。随着项目的深入,还可以结合 **Spire.PDF**的高级功能,如数字签名、加密与批注等,实现更安全、更智能的文档处理方案。

通过这一方法,你的团队将能够在保证质量与一致性的同时,大幅提升 PDF 文档的生成速度与管理效率,从而让自动化办公与报告生成更加高效、可控。

相关推荐
muyouking113 小时前
深入理解 HTML `<label>` 的 `for` 属性:提升表单可访问性与用户体验
前端·html·ux
软件技术NINI3 小时前
html css js网页制作成品——饮料官网html+css+js 4页网页设计(4页)附源码
javascript·css·html
软件技术NINI3 小时前
html css js网页制作成品——HTML+CSS辣条俱乐部网页设计(5页)附源码
javascript·css·html
ysdysyn4 小时前
.NET 10深度解析:性能革新与开发生态的全新篇章
c#·.net
我有一棵树5 小时前
使用Flex布局实现多行多列,每个列宽度相同
前端·css·html·scss·flex
L X..7 小时前
Unity 光照贴图异常修复笔记
unity·c#·游戏引擎
孤客网络科技工作室7 小时前
Python - 100天从新手到大师:第五十七天获取网络资源及解析HTML页面
开发语言·python·html
reasonsummer8 小时前
【办公类-115-06】20250920职称资料上传04——docx复制、docx转PDF(课程表11个)
开发语言·windows·python·c#
E_ICEBLUE8 小时前
高效压缩 PDF 文件大小(3 大实用的 Python 库)
python·pdf