iText如何从可填写的模板创建多页文档 [英] iText How to create multi-page document from a fillable template

查看:1585
本文介绍了iText如何从可填写的模板创建多页文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to create a multi-page PDF document in iText with filled forms, one for each person. I have looked up examples of how to do this on the internet and used those examples in my solution.

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

The PDF template is one created with Adobe Acrobat Pro.

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

I have been able to successfully fill in and return a single-page PDF document from my template using iText, but the multi-document process doesn't seem to work right.

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

This my program that demonstrates what I am trying to do:

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

在上面的代码中,你可以看到两个影响填充模板结果的关键语句:

In the code above, you can see two key statements that affect the result of the filled template:

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

使用上述两个语句,如果我将第一个设置为true而第二个设置为false,它填充了字段,但它们与标签不对齐。此外,在第一个模板复制之后,由于某种原因,之后的每个副本都有一些未填充的字段。

With the above two statements, if I set the first one to true and the second one to false, it fills the fields, but they are misaligned with the labels. Also, after the first template copy, each copy after that has some unfilled fields for some reason.

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

If I set them both to true:

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

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

it sets all of the fields in all of the template copies. This is the most successful result for me so far, but the filled fields are still misaligned with the labels and setting form flattening to true no longer allows a user to correct a field manually afterwards if the data in the application is wrong.

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

If I set the first one to false and the second one to true:

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

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

all of the fields are completely blank (worst result).

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

If I set them both to false:

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

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

then the fields are filled and appear in the right alignment with the labels. But the fields appear blank for some reason until you click on them. And the problem with some fields being wiped out in subsequent pages occurs like in the true false scenario (first scenario mentioned).

我想知道是否有可能得到这个在没有错位字段值的情况下工作,不会展平字段,也不会在后续页面上丢失字段。

I am wondering if it is possible to get this to work without misaligned field values, without flattening the fields, and without lost fields on subsequent pages.

我知道你可以使用

acroFields.setExtraMargin(extraMarginLeft, extraMarginTop)

但是使用

acroFields.setGenerateAppearances(false)

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

works perfectly for a single form without having to adjust margins and I want it to work for a multi-page document as well.

此外,使用

acroFields.setGenerateAppearances(true)

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

causes the text to move and be displaced a little bit in the textbox when you click on it. This happens for both single-page documents and multi-page documents. There seems to be a bug in either iText or PDF templates created with Adobe Pro when setting fields with setGenerateAppearances(true).

我目前正在使用iText 5.5.8。

I am currently using iText 5.5.8.

对此问题的任何帮助将不胜感激。感谢您花时间阅读本文。

Any help with this issue would be greatly appreciated. Thanks for taking the time to read this.

推荐答案

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

It's a very long question, and I guess that makes it difficult for people to answer it. I don't have a conclusive answer either, because I can't reproduce the problem. However, I can clarify a couple of things.

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

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

Suppose that you have a PDF form with a field named "name". It is possible for that field to appear on different places in the document. For instance: if a form has multiple pages, the field "name" could correspond with a widget annotation on every page (e.g. in the header).

字段name 只能有一个价值,例如:查尔斯卡林顿。如果该字段对应于不同的窗口小部件注释,则每个可视化应显示相同的名称。

The field "name" can only have a single value, for instance: "Charles Carrington." If the field corresponds with different widget annotations, then each of these visualizations should show the same name.

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

It is impossible for the field "name" to have the name "Charles Carrington" on one page, and "Bruno Lowagie" on another other page.

为什么这对你很重要?

您尝试使用 setFormFlattening()

如果您使用此方法值 false ,那么你做错了几件事:

If you use this method with the value false, then you are doing a couple of things wrong:


  1. 您没有告诉 PdfSmartCopy 您正在合并表单:如何将不同文件中的表格合并为一个PDF?

  2. 您违反了规则1 field = 1 value因为您首先使用不同的值填写不同表单中的字段(例如表单1:name = Charles Carrington;表单2:na我= Bruno Lowagie),然后你将这些表格合并成一个表格,你突然希望一个字段具有不同的值(例如mergedform:name = Charles Carrington在第1页;名称= Bruno Lowagie,第2页)。这违反了ISO-32000-1。

  1. You don't tell PdfSmartCopy that you are merging forms: How to merge forms from different files into one PDF?
  2. You are violating the rule "1 field = 1 value" because you first fill out fields in different forms with different values (e.g. form 1: name = Charles Carrington; form 2: name = Bruno Lowagie), then you merge these forms into a form where you suddenly expect one field to have different values (e.g. mergedform: name = Charles Carrington on page 1; name = Bruno Lowagie on page 2). This is in violation with ISO-32000-1.

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

You can avoid this problem by:


  • 重命名字段,如果对您保持交互性很重要。

  • 展平字段:在这种情况下,删除所有字段。而是添加值的外观。所有交互性都将丢失。

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

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

Suppose that you have a PDF form with a field named "birthdate" The value of that field is "1970-06-10" (and that's also the way how it's stored in a database). However, when you fill out the field in a PDF document, you want it to show as "June 10, 1970".

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

This is possible. The value of the /V key of the field dictionary will be the PDF string 1970-06-10. However, the /DA key will define an appearance that shows "June 10, 1970".

甚至可以使用具有单个值( 1970-06-10 )的字段,该字段与具有不同外观的不同窗口小部件注释相对应:6月10日,1970,1970年7月10日,10 juni 1970,依此类推。

It is even possible to have a field with a single value (1970-06-10) corresponding with different widget annotations that have a different appearance: "June 10, 1970", "10 juin 1970", "10 juni 1970", and so on.

为什么这对你很重要?

您一直在试验 setGenerateAppearances()

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

When you use this method with the value false, you instruct iText to omit the /DA: no appearance is created. When you flatten the form, the fields are empty. When you don't flatten the form, the PDF viewer will create the appearance. Since Adobe and other vendors haven't always been consistent in the way they render PDF, it is very hard to predict what that appearance will look like. One viewer will show the value at one position within the rectangle defined for the widget annotation; another viewer will show it with a different offset.

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

When you use this method with the value true, you instruct iText to create the appearance in a consistent way.

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

However: if you don't flatten the form, you can have the effect described in my answer to the question Why does iText enter a cross symbol when CheckType style is check mark? In this example, you see that the appearance of a check box depends on whether or not the field is high-lighted. The same goes for text fields: the appearance can be different whether or not you select it. Also: when you change the value, you get the appearance as created by the viewer. E.g. when you click on "June 10, 1970" because you want to change it, you will suddenly see "1970-06-10" because that's the value that is stored for the field and that value is generated by the viewer.

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

If you flatten the form, then iText creates the appearance and it removes all interactivity. In this case, the viewer doesn't create any appearance: there are no more fields in the form.

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

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

This is the mystery that remains after reading your question. You claim that the appearance when you fill and flatten a single form is different from the appearance when you fill and flatten many forms and then concatenate them. I can't reproduce that problem. The only answer I can give you to that question is: It works for me. (If you don't believe me, then please watch this tutorial.)

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

Please adapt your example based on the information given in 1. and 2., then post a new, shorter question if the problem persists.

这篇关于iText如何从可填写的模板创建多页文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆