iText如何从可填写的模板创建多页文档

我正在尝试在iText中创建一个多页PDF文档,其中包含填写的表单,每个人一个。 我已经查找了如何在互联网上执行此操作的示例,并在我的解决方案中使用了这些示例。

PDF模板是使用Adobe Acrobat Pro创建的模板。

我已经能够使用iText从我的模板中成功填写并返回单页PDF文档,但多文档过程似乎无法正常工作。

这个我的程序演示了我想要做的事情:

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,则它会填充字段,但它们与标签不对齐。 此外,在第一个模板复制之后,由于某种原因,之后的每个副本都有一些未填充的字段。

如果我将它们都设置为true:

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

它设置所有模板副本中的所有字段。 到目前为止,这对我来说是最成功的结果,但填充字段仍然与标签不对齐,并且设置forms展平为真不再允许用户在应用程序中的数据错误后手动更正字段。

如果我将第一个设置为false而将第二个设置为true:

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

所有字段都是完全空白的(最差结果)。

如果我将它们都设置为false:

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

然后填充字段并显示与标签的右对齐。 但是这些字段由于某种原因显示为空白,直到您单击它们为止。 并且在后续页面中消除了某些字段的问题,就像真正的错误场景(提到的第一个场景)一样。

我想知道是否有可能在没有错位字段值的情况下使其工作,而不会使字段变平,并且在后续页面上不会丢失字段。

我知道您可以使用后调整边距

 acroFields.setExtraMargin(extraMarginLeft, extraMarginTop) 

但使用

 acroFields.setGenerateAppearances(false) 

适用于单个表单,无需调整页边距,我希望它也适用于多页文档。

另外,使用

 acroFields.setGenerateAppearances(true) 

当您单击文本框时,会导致文本移动并在文本框中稍微移位。 对于单页文档和多页文档都会发生这种情况。 使用setGenerateAppearances(true)设置字段时,使用Adobe Pro创建的iText或PDF模板中似乎存在错误。

我目前正在使用iText 5.5.8。

任何有关此问题的帮助将不胜感激。 感谢您抽时间阅读。

这是一个很长的问题,我想这让人们很难回答它。 我也没有确定的答案,因为我无法重现这个问题。 但是,我可以澄清一些事情。

1.在PDF中,一个字段可以与多个窗口小部件注释对应。 一个字段只能有一个值。

假设您有一个PDF表单,其中包含名为“name”的字段。 该字段可能出现在文档中的不同位置。 例如:如果表单具有多个页面,则字段“name”可以对应于每个页面上的窗口小部件注释(例如,在标题中)。

字段“name”只能有一个值,例如:“Charles Carrington”。 如果该字段对应于不同的窗口小部件注释,则这些可视化中的每一个都应显示相同的名称。

字段“name”不可能在一个页面上显示“Charles Carrington”,而在另一个页面上显示“Bruno Lowagie”。

为什么这对你很重要?

您尝试使用setFormFlattening()

如果你使用值为false这个方法,那么你做了一些错误:

  1. 您没有告诉PdfSmartCopy您正在合并表单: 如何将不同文件中的表单合并为一个PDF?
  2. 您违反了规则“1 field = 1 value”,因为您首先使用不同的值填写不同forms的字段(例如,表单1:name = Charles Carrington;表单2:name = Bruno Lowagie),然后将这些表单合并为表单,您突然希望一个字段具有不同的值(例如,第1页的mergedform:name = Charles Carrington;第2页的名称= Bruno Lowagie)。 这违反了ISO-32000-1。

您可以通过以下方式避免此问题

  • 如果对您保持交互性很重要,请重命名字段。
  • 展平字段:在这种情况下,将删除所有字段。 而是添加值的外观。 所有交互都丢失了。

2.在PDF中,字段具有值,但也可以具有一个或多个外观。

假设您有一个PDF表单,其中包含一个名为“birthdate”的字段。该字段的值为“1970-06-10”(这也是它存储在数据库中的方式)。 但是,当您在PDF文档中填写该字段时,您希望它显示为“1970年6月10日”。

这个有可能。 字典字典的/V键的值将是PDF字符串1970-06-10 。 但是, /DA键将定义显示“1970年6月10日”的外观

甚至可能有一个具有单个值( 1970-06-10 )的字段,该字段对应于具有不同外观的不同窗口小部件注释:“1970年6月10日”,“1970年7月10日”,“10 juni 1970”,以及等等。

为什么这对你很重要?

您一直在尝试使用setGenerateAppearances()

当您使用值为false此方法时,您指示iText省略/DA :不创建外观。 展平表单时,字段为空。 如果不平整表单,PDF查看器将创建外观。 由于Adobe和其他供应商在呈现PDF方面并不总是一致,因此很难预测外观会是什么样子。 一个查看器将在为窗口小部件注释定义的矩形内的一个位置显示值; 另一个观众将以不同的偏移显示它。

当您使用值为true此方法时,您将指示iText以一致的方式创建外观。

但是:如果你没有展平表格,你可以在我对问题的答案中描述的效果为什么当CheckType样式是复选标记时,iText为什么输入十字符号? 在此示例中,您会看到复选框的外观取决于字段是否高亮。 文本字段也是如此:无论您是否选择它,外观都可能不同。 另外:当您更改值时,您将获得查看器创建的外观。 例如,当您点击“1970年6月10日”因为您想要更改它时,您将突然看到“1970-06-10”,因为这是为该字段存储的值,并且该值由查看器生成。

如果您展平表单,则iText会创建外观并删除所有交互性。 在这种情况下,查看器不会创建任何外观:表单中没有其他字段。

3. iText始终以相同的方式创建扁平外观。

这是阅读你的问题后仍然存在的谜。 您声称填充和压平单个表单时的外观与填充和压平多个表单然后连接它们时的外观不同。 我无法重现那个问题。 我可以给你的唯一答案是: 它对我有用。 (如果你不相信我,那么请看这个教程 。)

请根据1.2中给出的信息调整您的示例,如果问题仍然存在,请发布一个新的更短的问题。