代码之家  ›  专栏  ›  技术社区  ›  Christopher Done

从PDF表单中提取PDF表单字段名

  •  21
  • Christopher Done  · 技术社区  · 14 年前

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

    如何获取字段名?最好是命令行,.net或php解决方案。

    6 回复  |  直到 8 年前
        1
  •  41
  •   TEHEK    14 年前

    容易的!你已经在使用PDFTK了

    # pdftk input.pdf dump_data_fields
    

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

    我唯一缺少的就是场坐标…

        2
  •  7
  •   Dev_Corps    9 年前

    这对我很有用:

     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个小时才纠正过来,所以希望我能节省你一些时间:)

        3
  •  1
  •   Christopher Done    14 年前

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

        4
  •  1
  •   Eric Flamm    14 年前

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

        5
  •  1
  •   Trung Lê    12 年前

    虽然我的解决方案不是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 (https://github.com/joneslee85/nguyen)gem a try,如果您正在Ruby中寻找一个轻量级的lib。

        6
  •  0
  •   gallit    8 年前

    C/iTestSpple

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