【问题标题】:IText merge documents with acrofieldsIText 将文档与 acrofields 合并
【发布时间】:2015-02-17 16:28:23
【问题描述】:

我目前有一个 PdfReader 和一个 PdfStamper,用于填写 acrofields。我现在必须将另一个 pdf 复制到我一直在填写的表格的末尾,当我这样做时,我会丢失我复制的新表格上的 acrofield。这是代码。

public static void addSectionThirteenPdf(PdfStamper stamper, Rectangle pageSize, int pageIndex){
     PdfReader reader = new PdfReader(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/resources/documents/Section13.pdf"));
     AcroFields fields = reader.getAcroFields();

     fields.renameField("SecurityGuidancePage3", "SecurityGuidancePage" + pageIndex);

     stamper.insertPage(pageIndex, pageSize);
     stamper.replacePage(reader, 1, pageIndex);
}

我创建原始文档的方式是这样的。

     OutputStream output = FacesContext.getCurrentInstance().getExternalContext().getResponseOutputStream();

     PdfReader pdfTemplate = new PdfReader(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/resources/documents/dd254.pdf"));

     PdfStamper stamper = new PdfStamper(pdfTemplate, output);
     stamper.setFormFlattening(true);

     AcroFields fields = stamper.getAcroFields();

有没有办法使用第一段代码合并并将两个 acrofields 合并在一起?

【问题讨论】:

    标签: java adobe itext


    【解决方案1】:

    根据您的确切需求,可能会有不同的情况,但无论如何:您做错了。您应该使用PdfCopyPdfSmartCopy 来合并文档。

    下面video tutorial解释了不同的场景。

    您可以在iText sandbox 中找到大部分示例。

    合并不同的表单(具有不同的字段)

    如果您想合并 不同的 表单而不将它们展平,您应该使用 PdfCopy,就像在 MergeForms 示例中所做的那样:

    public void createPdf(String filename, PdfReader[] readers) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
        copy.setMergeFields();
        document.open();
        for (PdfReader reader : readers) {
            copy.addDocument(reader);
        }
        document.close();
        for (PdfReader reader : readers) {
            reader.close();
        }
    }
    

    在这种情况下,readers 是一个 PdfReader 实例数组,其中包含 不同 表单(具有不同的字段名称),因此我们使用 PdfCopy 并确保我们不忘记使用setMergeFields() 方法,否则字段不会被复制。

    合并相同的表单(具有相同的字段)

    在这种情况下,我们需要重命名字段,因为我们可能希望在不同的页面上有不同的值。在 PDF 中,一个字段只能有一个值。如果合并相同的表单,则同一字段有多个可视化,但每个可视化将显示相同的值(因为实际上只有一个字段)。

    我们来看看MergeForms2的例子:

    public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
        copy.setMergeFields();
        document.open();
        List<PdfReader> readers = new ArrayList<PdfReader>();
        for (int i = 0; i < 3; ) {
            PdfReader reader = new PdfReader(renameFields(src, ++i));
            readers.add(reader);
            copy.addDocument(reader);
        }
        document.close();
        for (PdfReader reader : readers) {
            reader.close();
        }
    }
    
    public byte[] renameFields(String src, int i) throws IOException, DocumentException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, baos);
        AcroFields form = stamper.getAcroFields();
        Set<String> keys = new HashSet<String>(form.getFields().keySet());
        for (String key : keys) {
            form.renameField(key, String.format("%s_%d", key, i));
        }
        stamper.close();
        reader.close();
        return baos.toByteArray();
    }
    

    如您所见,renameFields() 方法在内存中创建了一个新文档。该文档使用PdfSmartCopy 与其他文档合并。如果您在此处使用PdfCopy,您的文档将会变得臃肿(我们很快就会发现)。

    合并扁平表单

    FillFlattenMerge1 中,我们使用PdfStamper 填写表格。结果是一个保存在内存中并使用PdfCopy 合并的PDF 文件。虽然如果您要合并不同的表单,这个例子很好,这实际上是一个关于如何不这样做的例子(如video tutorial中所述)。

    FillFlattenMerge2 展示了如何合并正确填写和展平的相同表格:

    public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
        Document document = new Document();
        PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
        document.open();
        ByteArrayOutputStream baos;
        PdfReader reader;
        PdfStamper stamper;
        AcroFields fields;
        StringTokenizer tokenizer;
        BufferedReader br = new BufferedReader(new FileReader(DATA));
        String line = br.readLine();
        while ((line = br.readLine()) != null) {
            // create a PDF in memory
            baos = new ByteArrayOutputStream();
            reader = new PdfReader(SRC);
            stamper = new PdfStamper(reader, baos);
            fields = stamper.getAcroFields();
            tokenizer = new StringTokenizer(line, ";");
            fields.setField("name", tokenizer.nextToken());
            fields.setField("abbr", tokenizer.nextToken());
            fields.setField("capital", tokenizer.nextToken());
            fields.setField("city", tokenizer.nextToken());
            fields.setField("population", tokenizer.nextToken());
            fields.setField("surface", tokenizer.nextToken());
            fields.setField("timezone1", tokenizer.nextToken());
            fields.setField("timezone2", tokenizer.nextToken());
            fields.setField("dst", tokenizer.nextToken());
            stamper.setFormFlattening(true);
            stamper.close();
            reader.close();
            // add the PDF to PdfCopy
            reader = new PdfReader(baos.toByteArray());
            copy.addDocument(reader);
            reader.close();
        }
        br.close();
        document.close();
    }
    

    这是三种情况。您的问题对于任何人来说都太不清楚了,但您无法决定哪种方案最适合您的需求。我建议您在编码之前花时间学习。观看视频,尝试示例,如果您仍有疑问,可以发布更明智的问题。

    【讨论】:

    • copy.setMergeFields();在我的 PdfCopy 中不存在,我已经查找了这些解决方案。我正在使用 com.itextpdfitextpdf5.0.6 我正在查看它是否因为它现在已经过时了.
    • 它已经过时了。 iText 5.0.6 日期为 2011 年 2 月 4 日,也就是 4 年前!
    • 哈哈哈是的,我一开始看就注意到了哈哈。我将看看我是否可以使用这个新代码:)。我测试后会通知你的!
    • 超级有帮助!虽然我希望有一种方法可以通过使用 stamper.insertPage 或类似的东西来复制 acrofields。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2013-12-08
    • 2015-12-02
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    • 2018-12-22
    • 1970-01-01
    相关资源
    最近更新 更多