在开发员工登记、业务申请或信息采集系统时,经常需要将用户提交的数据自动填写到已有的 PDF 表单中。
如果 PDF 包含交互式表单字段(AcroForm),就可以通过 C# 直接修改字段内容,而不需要计算文字在页面上的坐标。常见的表单字段包括文本框、单选按钮、复选框、下拉框和列表框。
本文以一份员工信息登记表为例,介绍如何使用 C# 读取并填写不同类型的 PDF 表单字段,最后保存为新的 PDF 文件。
一、安装 PDF 处理库
本文使用免费版 Free Spire.PDF for .NET。
在 Visual Studio 中打开"工具 → NuGet 包管理器 → 程序包管理器控制台",执行:
Install-Package FreeSpire.PDF -Version 12.4.0
也可以通过 .NET CLI 安装:
lua
dotnet add package FreeSpire.PDF --version 12.4.0
免费版对处理的 PDF 有 10 页限制,因此建议使用不超过 10 页的表单模板。
二、C# 填写 PDF 交互式表单的实现步骤
假设已有一份名为 员工信息登记表.pdf 的 PDF 文件,其中包含以下表单字段:
| 表单字段 | 字段类型 | 填写内容 |
|---|---|---|
| 姓名 | 文本框 | 李晓雯 |
| 联系地址 | 文本框 | 上海市浦东新区 |
| 性别 | 单选按钮 | 女 |
| 同意条款 | 复选框 | 勾选 |
| 所属部门 | 下拉框 | 技术部 |
| 兴趣爱好 | 列表框 | 摄影 |
接下来按照加载 PDF、获取字段、填写内容和保存文件的顺序进行操作。
步骤 1:导入命名空间
首先导入 PDF 文档处理、表单字段操作和字体设置所需的命名空间:
sql
using System;
using Spire.Pdf;
using Spire.Pdf.Fields;
using Spire.Pdf.Widget;
using Spire.Pdf.Graphics;
其中,Spire.Pdf.Widget 命名空间包含用于操作已有 PDF 表单字段的相关类型,包括文本框、复选框、单选按钮等控件。
步骤 2:加载 PDF 并获取表单字段
创建 PdfDocument 对象,通过 LoadFromFile() 加载 PDF 模板,再获取交互式表单及其字段集合。
ini
// 加载 PDF 表单模板
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("员工信息登记表.pdf");
// 获取交互式表单
PdfFormWidget form = pdf.Form as PdfFormWidget;
// 获取表单字段集合
PdfFormFieldWidgetCollection fields = form.FieldsWidget;
FieldsWidget 包含 PDF 中已有的交互式表单字段,可以通过索引逐一访问。
需要注意的是,PDF 页面上显示的字段标签,不一定与字段内部名称相同 。例如,页面上标注"姓名",但对应的字段名称可能是 name、Text1 或其他内容。
后续代码需要根据字段的实际名称进行匹配。如果使用自己的 PDF 模板,应先确认字段名称是否一致。
以上代码假设文件中包含 AcroForm 字段。完整示例还会加入空值检查,避免表单不存在时发生异常。
步骤 3:遍历并填写表单字段
不同类型的表单控件,需要通过不同的属性设置内容。
| 表单字段类型 | 设置属性 | 示例 |
|---|---|---|
文本框 PdfTextBoxFieldWidget |
Text |
textBox.Text = "李晓雯"; |
单选按钮 PdfRadioButtonListFieldWidget |
SelectedIndex |
radio.SelectedIndex = 1; |
复选框 PdfCheckBoxWidgetFieldWidget |
Checked |
checkBox.Checked = true; |
下拉框 PdfComboBoxWidgetFieldWidget |
SelectedIndex |
comboBox.SelectedIndex = new int[] { 1 }; |
列表框 PdfListBoxWidgetFieldWidget |
SelectedIndex |
listBox.SelectedIndex = new int[] { 0 }; |
例如,要向名称为"姓名"的文本框填写内容,可以通过 for 循环遍历字段,判断字段类型和名称后再赋值:
ini
for (int i = 0; i < fields.Count; i++)
{
PdfField field = fields[i];
if (field is PdfTextBoxFieldWidget textBox &&
field.Name == "姓名")
{
textBox.Text = "李晓雯";
}
}
对于单选按钮、下拉框和列表框,需要特别注意选项索引的设置:
- 索引从 0 开始。 例如,
SelectedIndex = 1表示选择第二个选项。 - 属性类型有所不同。 单选按钮使用整数索引,而下拉框和列表框使用
int[]整数数组。
此外,填写中文时还需要考虑字体支持。如果原始文本框使用的字体不支持汉字,即使程序成功赋值,生成的 PDF 也可能显示为空白或乱码。完整示例中会为文本框设置支持中文的字体。
步骤 4:保存填写后的 PDF
字段填写完成后,调用 SaveToFile() 保存 PDF,并通过 Close() 关闭文档。
scss
// 保存填写后的 PDF
pdf.SaveToFile("员工信息登记表_已填写.pdf", FileFormat.PDF);
// 关闭文档
pdf.Close();
这里使用新的输出文件名,避免覆盖原始表单模板。
保存后的 PDF 仍然保留交互式字段,可以在支持 AcroForm 的 PDF 阅读器中继续填写或修改。
三、完整 C# 代码示例
下面通过一段完整代码,演示如何在同一份 PDF 中填写文本框、单选按钮、复选框、下拉框和列表框。
假设 PDF 表单中的字段名称与前文表格一致,并且选项顺序如下:
- 性别: 男、女
- 所属部门: 行政部、技术部、市场部
- 兴趣爱好: 摄影、阅读、旅行
ini
using System;
using Spire.Pdf;
using Spire.Pdf.Fields;
using Spire.Pdf.Widget;
using Spire.Pdf.Graphics;
class Program
{
static void Main()
{
PdfDocument pdf = new PdfDocument();
try
{
// 加载 PDF 表单模板
pdf.LoadFromFile("员工信息登记表.pdf");
// 获取交互式表单
PdfFormWidget form = pdf.Form as PdfFormWidget;
if (form == null || form.FieldsWidget.Count == 0)
{
Console.WriteLine("PDF 中没有可填写的表单字段。");
return;
}
PdfFormFieldWidgetCollection fields = form.FieldsWidget;
// 创建支持中文的字体(Windows 环境)
PdfTrueTypeFont chineseFont = new PdfTrueTypeFont(
new System.Drawing.Font("Microsoft YaHei", 11),
true
);
// 遍历所有表单字段
for (int i = 0; i < fields.Count; i++)
{
PdfField field = fields[i];
// 填写文本框
if (field is PdfTextBoxFieldWidget textBox)
{
switch (field.Name)
{
case "姓名":
textBox.Font = chineseFont;
textBox.Text = "李晓雯";
break;
case "联系地址":
textBox.Font = chineseFont;
textBox.Text = "上海市浦东新区";
break;
}
}
// 设置单选按钮
else if (field is PdfRadioButtonListFieldWidget radio)
{
if (field.Name == "性别")
{
// 选择第二项:女
radio.SelectedIndex = 1;
}
}
// 勾选复选框
else if (field is PdfCheckBoxWidgetFieldWidget checkBox)
{
if (field.Name == "同意条款")
{
checkBox.Checked = true;
}
}
// 设置下拉框
else if (field is PdfComboBoxWidgetFieldWidget comboBox)
{
if (field.Name == "所属部门")
{
// 选择第二项:技术部
comboBox.SelectedIndex = new int[] { 1 };
}
}
// 设置列表框
else if (field is PdfListBoxWidgetFieldWidget listBox)
{
if (field.Name == "兴趣爱好")
{
// 选择第一项:摄影
listBox.SelectedIndex = new int[] { 0 };
}
}
}
// 保存填写后的 PDF
pdf.SaveToFile("员工信息登记表_已填写.pdf", FileFormat.PDF);
Console.WriteLine("PDF 表单填写完成。");
}
finally
{
pdf.Close();
}
}
}
运行程序后,会生成 员工信息登记表_已填写.pdf,其中包含填写好的姓名、联系地址以及各类表单选项。
需要注意,代码中的字段名称和选项索引必须与实际 PDF 模板一致。如果表单来自其他系统,应根据其内部字段名称和选项顺序调整代码。
另外,本例使用 Windows 系统中的微软雅黑(Microsoft YaHei)字体。如果运行环境中没有该字体,需要替换为其他支持中文的字体。
四、C# 填写 PDF 表单时的常见问题
1. 程序运行成功,但 PDF 中没有填入内容
这种情况通常是因为代码中的字段名称与 PDF 实际字段名称不一致。
可以通过以下代码输出表单中所有字段的名称和类型:
ini
for (int i = 0; i < fields.Count; i++)
{
PdfField field = fields[i];
Console.WriteLine(
$"{field.Name} - {field.GetType().Name}"
);
}
根据输出结果检查代码中的 field.Name 判断条件。字段名称通常需要严格匹配,包括大小写和空格。
2. 填写中文后出现乱码或内容不显示
首先检查文本框使用的字体是否支持中文。
例如,某些 PDF 模板默认使用的西文字体没有中文字形,直接填写中文可能导致显示异常。
可以尝试为文本框指定支持中文的字体:
ini
textBox.Font = new PdfTrueTypeFont(
new System.Drawing.Font("Microsoft YaHei", 11),
true
);
textBox.Text = "李晓雯";
此代码需要导入 Spire.Pdf.Graphics 命名空间,并确保运行环境中安装了对应字体。
如果仍然显示异常,还应检查文本框的外观设置,并尝试使用其他 PDF 阅读器打开生成的文件,排除阅读器渲染差异。
3. 单选按钮或下拉框选中了错误的选项
通常是因为设置的索引与实际选项顺序不一致。
例如:
ini
radio.SelectedIndex = 1;
这表示选中第二个单选按钮,并不意味着一定选择"女"。
不同 PDF 模板可能采用不同的选项顺序。填写前应先确认各个选项对应的索引,避免出现内容与预期不符的情况。
4. PDF 中有输入框,但程序无法获取表单字段
并不是所有看起来像表单的 PDF 都包含可交互字段。
常见情况包括:
- PDF 只是普通文档,页面上的输入区域由线条和矩形组成。
- 文件是扫描件,输入区域实际上是图片的一部分。
- PDF 表单已经被扁平化,原来的交互式字段不再存在。
- 文件使用 XFA 等其他表单结构,而不是普通 AcroForm。
如果无法获取表单字段,建议先检查 PDF 的实际结构,确认它是否包含可通过 FieldsWidget 访问的 AcroForm 字段。
总结
使用 C# 填写 PDF 交互式表单,主要是通过 FieldsWidget 获取表单字段,根据字段名称和类型设置对应内容,再将结果保存为新的 PDF 文件。
这种方式适合员工登记、业务申请等使用固定 PDF 模板的场景。在实际项目中,还可以将示例中的固定值替换为数据库记录或用户提交的数据,实现 PDF 表单的自动填写,减少重复的人工录入工作。