.net 从PDF表单中提取PDF表单字段名称

.net 从PDF表单中提取PDF表单字段名称,.net,php,pdf,.net,Php,Pdf,我使用pdftk用XFDF文件填写PDF表单。然而,对于这个项目,我事先不知道会出现哪些字段,所以我需要分析PDF本身,看看需要填写哪些字段,相应地向用户提供一个界面,然后根据该界面生成一个XFDF文件,以填写PDF表单 如何获取字段名?最好是命令行、.NET或PHP解决方案。我可以让我的客户端使用Acrobat和PDF导出XFDF文件(其中包含字段名),这完全避免了这个问题。我使用WebSupergoo的ABCpdf使用了以下代码,但我认为大多数库都有类似的类: protected void

我使用pdftk用XFDF文件填写PDF表单。然而,对于这个项目,我事先不知道会出现哪些字段,所以我需要分析PDF本身,看看需要填写哪些字段,相应地向用户提供一个界面,然后根据该界面生成一个XFDF文件,以填写PDF表单


如何获取字段名?最好是命令行、.NET或PHP解决方案。

我可以让我的客户端使用Acrobat和PDF导出XFDF文件(其中包含字段名),这完全避免了这个问题。

我使用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) 用输出文件中的字段名填充所有文本字段-打印输出文件,所有文本字段都将被标记。

简单!您已经在使用pdftk了

# pdftk input.pdf dump_data_fields
它将输出字段名、字段类型、一些属性(比如下拉列表或文本对齐的选项)甚至工具提示文本(我发现这非常有用)


我唯一缺少的是字段坐标…

虽然我的解决方案不是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
#代码借用自'nguyen'gem[https://github.com/joneslee85/nguyen]
#生成XFDF内容
def to_xfdf(字段={},选项={})
builder=Nokogiri::XML::builder.new(:encoding=>'UTF-8')do | XML|
xfdf('xmlns'=>'http://ns.adobe.com/xfdf/“,”xml:space“=>”保留“){
xml.f(:href=>options[:file])如果选项[:file]
id(:original=>options[:id],:modified=>options[:id])如果选项[:id]
xml.fields{
字段。每个do |字段,值|
field(:name=>field){
if value.u是一个数组吗
value.each{| item | xml.value(item.to_s)}
其他的
xml.value(value.to_s)
结束
}
结束
}
}
结束
builder.to_xml
结束
#将fdf内容写入路径
def保存到(路径)
(File.open(path,'w')这对我很有用:

 pdftk 1.pdf dump_data_fields output test2.txt
然后,当使用密码对文件进行加密时,这就是您可以从中读取的方式

 pdftk 1.pdf input_pw YOUR_PASSWORD_GOES_HERE dump_data_fields output test2.txt
这花了我两个小时才搞定,所以希望我能为您节省一些时间:)

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();
    }

考虑到
pdftk
是废弃软件,您可以使用
qpdf
库以JSON格式转储元数据,并使用
jq
仅过滤表单相关数据:

qpdf inout.pdf --json | jq '.acroform.fields'

qpdf
是一个轻量级的跨平台自由/开源软件库。

Christopher,如果你找到了一个解决方案,我鼓励你将其发布并标记为答案,以便其他人将来可以从中受益。或者您可以选择
delete
链接删除您的问题。这应该是所选的答案。或者,如果您有Adobe Professional,则可以单击表单>管理表单数据>导出数据以将数据导出到FDF文件。然后打开FDF文件,获取与填充值关联的字段名。太棒了,这对我帮助很大(找解决方案花了一天时间),这个命令去哪里了?它在pdftk的免费版本上可用吗?你是指Acrobat Reader还是其他相关的Acrobat产品?@christopher done请告诉你的客户名称,以及如何生成XFDF文件