我正在使用pdftk填写带有XFDF文件的PDF表单。但是,对于这个项目,我事先并不知道将出现哪些字段,因此我需要分析PDF本身以查看需要填写的字段,相应地向用户显示接口,然后从中生成XFDF文件填写PDF表格。
如何获取字段名称?最好是命令行,.NET或PHP解决方案。
答案 0 :(得分:42)
轻松!您已经在使用pdftk了
# pdftk input.pdf dump_data_fields
它将输出字段名称,字段类型,它的一些属性(如下拉列表或文本对齐的选项),甚至是工具提示文本(我发现它非常有用)
我唯一缺少的是场地坐标...
答案 1 :(得分:7)
这对我有用:
pdftk 1.pdf dump_data_fields output test2.txt
然后,当用密码加密文件时,这就是你可以从中读取的方式
pdftk 1.pdf input_pw YOUR_PASSWORD_GOES_HERE dump_data_fields output test2.txt
这花了我2个小时才能走向正确,所以希望我能节省你一些时间:)
答案 2 :(得分:1)
我可以让我的客户端使用Acrobat和PDF导出XFDF文件(包含字段名称),这完全避免了这个问题。
答案 3 :(得分:1)
我使用了以下代码,使用了来自WebSupergoo的ABCpdf,但我想大多数库都有类似的类:
protected void Button1_Click(object sender, EventArgs e)
{
Doc thedoc = new Doc();
string saveFile = "~/docs/f1_filled.pdf";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
thedoc.Read(Server.MapPath("~/docs/F1_2010.pdf"));
foreach (Field fld in thedoc.Form.Fields)
{
if (!(fld.Page == null))
{
sb.AppendFormat("Field: {0}, Type: {1},page: {4},x: {2},y: {3}\n", fld.Name, fld.FieldType.ToString(), fld.Rect.Left, fld.Rect.Top, fld.Page.PageNumber);
}
else
{
sb.AppendFormat("Field: {0}, Type: {1},page: {4},x: {2},y: {3}\n", fld.Name, fld.FieldType.ToString(), fld.Rect.Left, fld.Rect.Top, "None");
}
if (fld.FieldType == FieldType.Text)
{
fld.Value = fld.Name;
}
}
this.TextBox1.Text = sb.ToString();
this.TextBox1.Visible = true;
thedoc.Save(Server.MapPath(saveFile));
Response.Redirect(saveFile);
}
这有两件事: 1)使用所有表单字段的清单填充文本框,在页面上显示其名称,字段类型及其页码和位置(顺便说一下,0,0在左下方)。 2)在输出文件中填充所有文本字段及其字段名称 - 打印输出文件,并标记所有文本字段。
答案 4 :(得分:1)
我的答案非常晚,虽然我的解决方案不是PHP,但我希望如果有人在寻找Ruby的解决方案,它可能会派上用场。
首先是使用pdftk提取所有字段名称然后我们需要清理转储文本,以获得良好的可读哈希:
def extract_fields(filename)
field_output = `pdftk #{filename} dump_data_fields 2>&1`
@fields = field_output.split(/^---\n/).map do |field_text|
if field_text =~ /^FieldName: (\w+)$/
$1
end
end.compact.uniq
end
其次,现在我们可以使用任何XML解析来构造我们的XFDF:
# code borrowed from `nguyen` gem [https://github.com/joneslee85/nguyen]
# generate XFDF content
def to_xfdf(fields = {}, options = {})
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.xfdf('xmlns' => 'http://ns.adobe.com/xfdf/', 'xml:space' => 'preserve') {
xml.f(:href => options[:file]) if options[:file]
xml.ids(:original => options[:id], :modified => options[:id]) if options[:id]
xml.fields {
fields.each do |field, value|
xml.field(:name => field) {
if value.is_a? Array
value.each { |item| xml.value(item.to_s) }
else
xml.value(value.to_s)
end
}
end
}
}
end
builder.to_xml
end
# write fdf content to path
def save_to(path)
(File.open(path, 'w') << to_xfdf).close
end
Viola,这是主要的逻辑。如果你在Ruby中寻找一个轻量级的lib,我强烈建议你试试nguyen
(https://github.com/joneslee85/nguyen)gem。
答案 5 :(得分:1)
考虑到 pdftk
是废弃软件,可以使用 qpdf
库转储 JSON 格式的元数据,并使用 jq
仅过滤表单相关数据:
qpdf inout.pdf --json | jq '.acroform.fields'
qpdf
是一个轻量级的跨平台 FOSS 库。
答案 6 :(得分:0)
C#/ ITextSharp
public static void TracePdfFields(string pdfFilePath)
{
PdfReader pdfReader = new PdfReader(pdfFilePath);
MemoryStream pdfStream = new MemoryStream();
PdfStamper pdfStamper = new PdfStamper(pdfReader, pdfStream, '\0', true);
int i = 1;
foreach (var f in pdfStamper.AcroFields.Fields)
{
pdfStamper.AcroFields.SetField(f.Key, string.Format("{0} : {1}", i, f.Key));
i++;
//DoTrace("Field = [{0}] | Value = [{1}]", f.Key, f.Value.ToString());
}
pdfStamper.FormFlattening = false;
pdfStamper.Writer.CloseStream = false;
pdfStamper.Close();
FileStream fs = File.OpenWrite(string.Format(@"{0}/{1}-TracePdfFields_{2}.pdf",
ConfigManager.GetInstance().LogConfig.Dir,
new FileInfo(pdfFilePath).Name,
DateTime.Now.Ticks));
fs.Write(pdfStream.ToArray(), 0, (int)pdfStream.Length);
fs.Flush();
fs.Close();
}