2010-01-24 61 views
19

我正在使用pdftk填充PDF表單並使用XFDF文件。但是,對於這個項目,我不會預先知道哪些字段會出現,所以我需要分析PDF本身以查看需要填寫哪些字段,相應地向用戶提供一個接口,然後從中生成一個XFDF文件填寫PDF表格。從PDF表格提取PDF表單字段名稱

如何獲取字段名稱?最好是命令行,.NET或PHP解決方案。

+1

克里斯托弗,如果您找到了解決方案,我鼓勵您發佈它並將其標記爲答案,以便其他人可以從中受益。或者你可以選擇刪除鏈接來刪除你的問題。 – 2010-01-24 17:26:24

+0

會做。乾杯。 – 2010-01-24 17:41:10

回答

1

我可以讓我的客戶端使用Acrobat與PDF一起導出XFDF文件(其中包含字段名稱),從而完全避免了此問題。

1

我用下面的代碼,使用ABCpdf從WebSupergoo,但我想大多數圖書館有可比類:

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)用輸出文件中的字段名稱填充所有文本字段 - 打印輸出文件,並且所有文本字段都將被標記。

37

簡單!您正在使用PDFTK已經

# pdftk input.pdf dump_data_fields 

它將輸出字段名,字段類型,它的一些特性(如什麼是下拉列表或文本對齊選項),甚至一個工具提示文本(我認爲是非常有用)

我唯一缺少的是場座標...

+4

這應該是選定的答案。或者,如果您有Adobe Professional,則可以單擊表單>管理表單數據>導出數據將數據導出到FDF文件。然後打開FDF文件並獲取與填充值關聯的字段名稱。 – Furbeenator 2013-11-13 19:19:21

+0

太棒了,它非常幫助我(失去了一天尋找解決方案) – Epsiloncool 2014-07-14 14:02:34

+0

這個命令去哪裏?它是否可用於免費版本的pdftk? – 2015-05-20 22:53:54

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 

中提琴,這是主要的邏輯。如果您在Ruby中查找輕量級庫,我強烈建議您給nguyen(https://github.com/joneslee85/nguyen)gem試試。

7

這爲我工作:

​​

然後,當文件被用密碼加密的,這是怎麼了,你可以從它

pdftk 1.pdf input_pw YOUR_PASSWORD_GOES_HERE dump_data_fields output test2.txt 

這花了我2個小時得到正確的閱讀,所以希望我節省您的時間:)

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