2016-02-03 3 views
0

Я пытаюсь создать многостраничный PDF-документ в iText с заполненными формами, по одному для каждого человека. Я просмотрел примеры того, как это сделать в Интернете, и использовал эти примеры в своем решении.iText Как создать многостраничный документ из заполняемого шаблона

PDF-шаблон является одним из созданных с помощью Adobe Acrobat Pro.

Я смог успешно заполнить и вернуть одностраничный документ PDF из своего шаблона с помощью iText, но процесс с несколькими документами, похоже, не работает правильно.

Это моя программа, которая показывает, что я пытаюсь сделать:

import com.itextpdf.text.pdf.AcroFields; 
import com.itextpdf.text.pdf.PdfReader; 
import com.itextpdf.text.pdf.PdfStamper; 
import com.itextpdf.text.Document; 
import com.itextpdf.text.DocumentException; 
import com.itextpdf.text.pdf.PdfSmartCopy; 

import java.util.Date; 
import java.text.DateFormat; 
import java.text.SimpleDateFormat; 
import java.text.NumberFormat; 
import java.io.IOException; 
import java.io.ByteArrayOutputStream; 
import java.io.FileOutputStream; 

public class ITextTest 
{ 
    public static final String TEMPLATE = 
    "C:\\RAD7_5\\iTextTest\\iTextTest\\input\\LS213_1.pdf"; 

    public static void main(String[] args) 
    { 
     ITextTest iTextTest = new ITextTest(); 
     iTextTest.doItextTest(); 
    } 

    public void doItextTest() 
    { 
     try 
     { 
      PdfReader pdfReader; 
      PdfStamper pdfStamper; 
      ByteArrayOutputStream baos; 

      Document document = new Document(); 
      PdfSmartCopy pdfSmartCopy = new PdfSmartCopy(document, 
        new FileOutputStream("C:\\RAD7_5\\iTextTest\\iTextTest\\output\\LS213_1MultiTest.pdf")); 

      DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy"); 
      Date currDate = new Date(); 
      NumberFormat numberFormat = NumberFormat.getCurrencyInstance(); 
      double amount = 4127.29d; 

      document.open(); 

      for(int i = 1; i <= 5; i++) 
      { 
       pdfReader = new PdfReader(TEMPLATE); 
       baos = new ByteArrayOutputStream(); 
       pdfStamper = new PdfStamper(pdfReader, baos); 

       AcroFields acroFields = pdfStamper.getAcroFields(); 

       //key statement 1 
       acroFields.setGenerateAppearances(true); 

       //acroFields.setExtraMargin(5, 5); 
       acroFields.setField("Name and Address", "John Doe\n123 Anywhere St.\nAnytown, USA 12345"); 
       acroFields.setField("Case Number", "123456789"); 
       acroFields.setField("Employer", "Employer Co., Inc.\n456 Anyhow ln.\nAnyville, USA 67890"); 
       acroFields.setField("Date", dateFormat.format(currDate)); 
       acroFields.setField("Name", "John Doe"); 
       acroFields.setField("restitution check No", "65432" + i); 
       acroFields.setField("in the sum of", numberFormat.format(amount)); 

       //key statement 2 
       pdfStamper.setFormFlattening(false); 

       pdfStamper.close(); 
       pdfReader.close(); 

       pdfReader = new PdfReader(baos.toByteArray()); 
       pdfSmartCopy.addPage(pdfSmartCopy.getImportedPage(pdfReader, 1)); 
       pdfSmartCopy.freeReader(pdfReader); 
       pdfReader.close(); 
      } 

      document.close(); 
     } 
     catch(DocumentException dex) 
     { 
      dex.printStackTrace(); 
      System.exit(1); 
     } 
     catch(IOException ex) 
     { 
      ex.printStackTrace(); 
      System.exit(1); 
     } 
    } 
} 

В приведенном выше коде, вы можете увидеть два ключевых заявления, которые влияют на результат заполненного шаблона:

acroFields.setGenerateAppearances(true); 
pdfStamper.setFormFlattening(false); 

С помощью вышеуказанных двух утверждений, если я устанавливаю первый в true, а второй - в false, он заполняет поля, но они смещены с метками. Кроме того, после первой копии шаблона каждая копия после этого имеет некоторые незаполненные поля по какой-либо причине.

Если установить их как истину:

acroFields.setGenerateAppearances(true); 
pdfStamper.setFormFlattening(true); 

он устанавливает все поля во всех копиях шаблона. Это самый успешный результат для меня до сих пор, но заполненные поля по-прежнему не совпадают с метками, а выравнивание формы до истины больше не позволяет пользователю вручную корректировать поле вручную, если данные в приложении неверны.

Если установить первый в ложь, а второй к истинным:

acroFields.setGenerateAppearances(false); 
pdfStamper.setFormFlattening(true); 

все поля полностью пустой (худший результат).

Если установить их как ложь:

acroFields.setGenerateAppearances(false); 
pdfStamper.setFormFlattening(false); 

то поля заполняются и появляются в правильном выравнивании с этикетками. Но по каким-либо причинам поля будут пустыми, пока вы не нажмете на них. И проблема с некоторыми полями, которые были уничтожены на последующих страницах, происходит, как в истинном ложном сценарии (упомянутый первый сценарий).

Мне интересно, возможно ли, чтобы это работало без неправильных значений поля, без выравнивания полей и без потерянных полей на последующих страницах.

Я знаю, что вы можете настроить поля после использования

acroFields.setExtraMargin(extraMarginLeft, extraMarginTop) 

, но с использованием

acroFields.setGenerateAppearances(false) 

работает отлично для одной формы без изменения полей и я хочу работать для многостраничных документ также.

Кроме того, с помощью

acroFields.setGenerateAppearances(true) 

приводит текст двигаться и смещаться немного в текстовом поле при нажатии на нее. Это происходит как для одностраничных документов, так и для многостраничных документов. Кажется, что в iText или PDF-шаблонах, созданных с помощью Adobe Pro, появляется ошибка при настройке полей с помощью setGenerateAppearances (true).

В настоящее время я использую iText 5.5.8.

Любая помощь с этой проблемой была бы весьма признательна. Спасибо, что нашли время, чтобы прочитать это.

ответ

1

Это очень длинный вопрос, и я думаю, что это затрудняет людям отвечать на него. У меня нет окончательного ответа, потому что я не могу воспроизвести проблему. Однако я могу прояснить пару вещей.

1. В PDF одном поле может соответствовать несколько аннотаций виджета. Одно поле может иметь только одно значение.

Предположим, что у вас есть форма PDF с полем «имя». Возможно, что это поле появится в разных местах документа. Например: если форма имеет несколько страниц, поле «имя» может соответствовать аннотации виджета на каждой странице (например, в заголовке).

Поле «имя» может иметь только одно значение, например: «Чарльз Каррингтон». Если поле соответствует различным аннотациям виджета, то каждая из этих визуализаций должна показывать одно и то же имя.

Невозможно, чтобы поле «имя» имело имя «Чарльз Каррингтон» на одной странице и «Бруно Лоуджи» на другой странице.

Почему это важно для вас?

Вы экспериментировали с setFormFlattening().

Если вы используете этот метод со значением false, то вы делаете пару вещей неправильно:

  1. Вы не говорите PdfSmartCopy, что вы сливаете формы: How to merge forms from different files into one PDF?
  2. Вы нарушаете правило «1 поле = 1 значение», потому что вы сначала заполняете поля в разных формах с различными значениями (например, форма 1: имя = Charles Carrington; форма 2: name = Bruno Lowagie), затем вы объединяете эти формы в формы, где вы вдруг ожидаете, что одно поле будет иметь различные значения (например, mergedform: name = Charles Carrington на стр. 1; name = Bruno Lowagie на стр. 2). Это нарушает ISO-32000-1.

Вы можете избежать этой проблемы путем:

  • переименование полей, если это для вас важно, что сохраняется интерактивность.
  • сплющивание полей: в этом случае все поля удаляются. Вместо этого вы добавляете внешний вид значений. Вся интерактивность теряется.

2. В PDF поле имеет значение, но оно также может иметь одно или несколько изображений.

Предположим, что у вас есть форма PDF с полем с именем «birthdate». Значение этого поля - «1970-06-10» (и это также способ, которым он хранится в базе данных). Однако, когда вы заполняете поле в PDF-документе, вы хотите, чтобы оно отображалось как «10 июня 1970 года».

Это возможно. Значением ключа /V словаря поля будет строка PDF 1970-06-10. Однако ключ /DA определит внешний вид , который показывает «10 июня 1970 года».

Возможно даже иметь поле с одним значением (1970-06-10), соответствующее различным аннотациям виджета, которые имеют другой вид: «10 июня 1970», «10 июня 1970», «10 июня 1970 года» и скоро.

Почему это важно для вас?

Вы экспериментировали с setGenerateAppearances().

Когда вы используете этот метод со значением false, вы инструктируете iText опустить /DA: внешний вид не создается. Когда вы сглаживаете форму, поля пустые. Когда вы не сгладите форму, средство просмотра PDF создаст внешний вид. Поскольку Adobe и другие поставщики не всегда были последовательны в том, как они делают PDF, очень сложно предсказать, как будет выглядеть этот внешний вид. Один просмотрщик покажет значение в одной позиции в прямоугольнике, определенном для аннотации виджета; другой зритель покажет его с другим смещением.

Когда вы используете этот метод со значением true, вы инструктируете iText создавать внешний вид в согласованном виде.

Однако: если вы не выравнивать форму, вы можете иметь эффект, описанный в моем ответе на вопрос Why does iText enter a cross symbol when CheckType style is check mark? В этом примере вы видите, что появление флажка зависит от того, является ли поле высокий освещено. То же самое касается текстовых полей: внешний вид может быть другим, независимо от того, выбираете ли вы его. Также: когда вы меняете значение, вы получаете внешний вид, созданный зрителем. Например. когда вы нажимаете «10 июня 1970 года», потому что вы хотите изменить его, вы увидите «1970-06-10», потому что это значение, которое хранится для этого поля, и это значение генерируется зрителем.

Если вы сглаживаете форму, то iText создает внешний вид и удаляет всю интерактивность. В этом случае зритель не создает никакого внешнего вида: в форме больше полей.

3. iText всегда создает сплющенный вид таким же образом.

Это тайна, которая остается после прочтения вашего вопроса. Вы утверждаете, что внешний вид, когда вы заполняете и выравниваете одну форму, отличается от внешнего вида, когда вы заполняете и выравниваете многие формы, а затем объединяете их. Я не могу воспроизвести эту проблему. Единственный ответ, который я могу дать вам на этот вопрос: Это работает для меня. (Если вы мне не верите, пожалуйста, watch this tutorial.)

Пожалуйста, адаптируйте свой пример на основе информации, приведенной в . 1. и 2., а затем опубликовать новый, более короткий вопрос, если проблема не устранена.

+0

Первая ссылка, которую вы предоставили («Как объединить формы из разных файлов в один PDF?»), Решила проблему с полями на последующих страницах, которые были уничтожены. Переименование полей работало для сохранения интерактивности пользователя. И ваше объяснение setGenerateAppearances() решило проблему с несогласованными полями. Если мы закончим использование нескольких просмотрщиков PDF (зрителей, отличных от Adobe Reader), я верну его значение true и с помощью операторов setExtraMargin() настройте выравнивание. Ваш ответ был очень полезным, и теперь наши документы работают должным образом. Спасибо за вашу помощь. –

Смежные вопросы