gpt4 book ai didi

java - iText如何从可填充模板创建多页文档

转载 作者:行者123 更新时间:2023-12-01 10:29:08 28 4
gpt4 key购买 nike

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

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


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

如果我将第一个设置为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”的字段。该字段可能出现在文档中的不同位置。例如:如果表单具有多个页面,则字段“名称”可能与每个页面上的小部件注释相对应(例如,标题中)。

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

字段“名称”不可能在一页上具有名称“ Charles Carrington”,而在另一页上具有“ Bruno Lowagie”。

为什么这对您很重要?

您尝试了setFormFlattening()

如果将此方法与值false一起使用,则说明您做错了几件事:


您不会告诉PdfSmartCopy您正在合并表单:How to merge forms from different files into one PDF?
您违反规则“ 1字段= 1值”,因为您首先用不同的值(例如,表格1:名称= Charles Carrington;表格2:名称= Bruno Lowagie)以不同的形式填写了字段,然后将这些表格合并为您突然希望一个字段具有不同值的表单(例如,mergedform:第1页上的名称= 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日”,“ 10年6月1970年”,“ 10年6月1970年”,依此类推。

为什么这对您很重要?

您一直在尝试setGenerateAppearances()

当将此方法与值false一起使用时,将指示iText忽略/DA:不会创建外观。展平表格时,字段为空。当您不展平表格时,PDF查看器将创建外观。由于Adobe和其他供应商的PDF呈现方式并不总是一致的,因此很难预测其外观。一位查看者将在为小部件注释定义的矩形内的一个位置显示该值;另一个查看器将以不同的偏移量显示它。

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

但是:如果您不拼凑表格,则可以得到我对问题Why does iText enter a cross symbol when CheckType style is check mark?的回答中所述的效果
在此示例中,您会看到复选框的外观取决于该字段是否突出显示。文本字段也是如此:无论您是否选择,外观都可以不同。另外:更改值时,将获得查看器创建的外观。例如。当您因为要更改而单击“ 1970年6月10日”时,会突然看到“ 1970-06-10”,因为这是为该字段存储的值,并且该值是由查看器生成的。

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

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

这是阅读您的问题后仍然存在的奥秘。您声称填写和展平单个表单时的外观与填写并展平许多表单然后将它们连接在一起时的外观不同。我无法重现该问题。对于这个问题,我唯一能给您的答案是:它对我有用。 (如果您不相信我,请watch this tutorial。)

请根据1.和2.中提供的信息调整您的示例,然后如果问题仍然存在,则发布一个新的,简短的问题。

关于java - iText如何从可填充模板创建多页文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35185830/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com