Я использую pdftk для заполнения формы PDF с помощью файла XFDF. Однако для этого проекта я заранее не знаю, какие поля будут присутствовать, поэтому мне нужно проанализировать сам PDF, чтобы увидеть, какие поля нужно заполнить, представить интерфейс для пользователя соответствующим образом, а затем сгенерировать XFDF-файл из чтобы заполнить форму PDF.
Как получить имена полей? Предпочтительно решения командной строки, .NET или PHP.
Легко! Вы уже используете pdftk
# pdftk input.pdf dump_data_fields
Он выведет имя поля, тип поля, некоторые его свойства (например, какие параметры выпадающего списка или выравнивание текста) и даже текст всплывающей подсказки (который я считаю чрезвычайно полезным)
Единственное, что мне не хватает, это координаты полей …
Это сработало для меня:
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 часа, чтобы поправиться, поэтому, надеюсь, я сэкономлю вам время 🙂
Я могу заставить моего клиента экспортировать XFDF-файл (который содержит имена полей) с помощью Acrobat вместе с PDF-файлом, который полностью устраняет эту проблему.
Я использовал следующий код, используя 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); }
Это делает 2 вещи: 1) заполняет текстовое поле инвентаризацией всех полей формы, показывая их имя, тип поля, а также номер и позицию страницы на странице (0,0 слева внизу, кстати). 2) Заполняет все текстовые поля своим именем поля в выходном файле – распечатывает выходной файл, и все ваши текстовые поля будут помечены.
Очень поздний ответ от меня, хотя мое решение не 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 попробовать, если вы ищете легкий lib в Ruby.
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(); }