2010-01-24 9 views
19

J'utilise pdftk pour remplir un formulaire PDF avec un fichier XFDF. Cependant, pour ce projet je ne sais pas à l'avance quels champs seront présents, donc j'ai besoin d'analyser le PDF lui-même pour voir quels champs doivent être remplis, présenter une interface à l'utilisateur en conséquence, puis générer un fichier XFDF de cela pour remplir le formulaire PDF.Extraire les noms de champs de formulaire PDF à partir d'un formulaire PDF

Comment obtenir les noms de champs? De préférence, les solutions en ligne de commande, .NET ou PHP.

+1

Christopher, si vous avez trouvé une solution, je vous encourage à l'afficher et à la marquer comme une réponse afin que d'autres puissent en bénéficier à l'avenir. Ou vous pouvez choisir le lien 'delete' pour supprimer votre question. –

+0

Fera. À votre santé. –

Répondre

1

Je peux demander à mon client d'exporter le fichier XFDF (qui contient des noms de champs) en utilisant Acrobat avec le PDF, ce qui évite complètement ce problème.

1

J'ai utilisé le code suivant, en utilisant ABCpdf de WebSupergoo, mais j'imagine que la plupart des bibliothèques ont des classes comparables:

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

Cela fait 2 choses: 1) Remplit une zone de texte avec l'inventaire de tous les champs de formulaire, montrant leur nom, type de champ, et leur numéro de page et la position sur la page (0,0 est en bas à gauche, soit dit en passant). 2) Remplit tous les champs de texte avec leur nom de champ dans un fichier de sortie - imprime le fichier de sortie, et tous vos champs de texte seront étiquetés.

37

Facile! Vous utilisez pdftk déjà

# pdftk input.pdf dump_data_fields 

Il affichera Nom du champ, type de champ, certains de ses propriétés (comme ce sont les options pour la liste déroulante ou l'alignement du texte) et même un texte de l'infobulle (que je trouve extrêmement utile)

La seule chose qui me manque est coordonne le terrain ...

+4

Cela devrait être la réponse sélectionnée. Si vous utilisez Adobe Professional, vous pouvez également cliquer sur Formulaires> Gérer les données de formulaire> Exporter les données pour exporter les données dans un fichier FDF. Ensuite, ouvrez le fichier FDF et obtenez les noms de champs associés aux valeurs renseignées. – Furbeenator

+0

Génial, ça m'a beaucoup aidé (perdu une journée à chercher une solution) – Epsiloncool

+0

où est passée cette commande? Est-il disponible sur la version gratuite de pdftk? –

1

Une réponse très tard de moi, bien que ma solution n'est pas PHP, mais j'espère qu'il pourrait être utile si quelqu'un cherche une solution pour Ruby.

première consiste à utiliser pdftk pour extraire tous les champs nommerai alors nous avons besoin de nettoyer le texte de décharge, d'avoir un bon hachage lisible:

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 

Deuxièmement, nous pouvons maintenant utiliser une analyse syntaxique XML pour construire notre 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 

Alto, c'est la logique principale. Je vous recommande vivement de donner nguyen (https://github.com/joneslee85/nguyen) gem un essai si vous cherchez une bibliothèque légère en Ruby.

7

Cela a fonctionné pour moi:

pdftk 1.pdf dump_data_fields output test2.txt 

Ensuite, lorsque le fichier est crypté avec un mot de passe, voici comment vous pouvez lire ce

pdftk 1.pdf input_pw YOUR_PASSWORD_GOES_HERE dump_data_fields output test2.txt 

Cela m'a pris 2 heures pour obtenir le droit, alors espérons que je vous faire gagner du temps :)

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