在for循环中使用PdfStamper的最佳方法

时间:2015-11-07 12:54:16

标签: java itext

我有以下iText代码来读取文件并将其添加到主PDF文件中,因此它基本上是在绝对位置的现有PDF中添加PDF页面。主PDF中的绝对位置和页码将动态决定。有时可能是第1页的100,100(x,y)或第2页的250,250(x,y)。我循环遍历每个对象代表PDF文件的PDF对象,然后我将应用业务逻辑将PDF对象转换为PDF文件,即srcPdf。现在我需要将这个srcPdf添加到主PDF中的绝对位置(这里是pdfStamper):

for(ListOfPdfObject pdfObj: ListOfPdfObjects) {
    // code to create srcPdf so there will be new srcPdf for each iteration. srcPdf is flattened pdf of acro form field pdf.
    PdfReader reader2 = new PdfReader(srcPdf.getAbsolutePath());
    PdfImportedPage page = pdfStamper.getImportedPage(reader2, 1);
    pdfStamper.insertPage(1, reader2.getPageSize(1));
    pdfStamper.getUnderContent(1).addTemplate(page, 100, 100);
    pdfStamper.close(); // problem is here
    reader2.close();
}

此处pdfStamperfor-loop之外创建,如下所示:

PdfReader pdfReader = new PdfReader(new FileInputStream(tempPdf));
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(destPdf));

问题是如果我在pdfStamper之后关闭for-loop会引发RandomAccessSource not opened异常。如果我在for循环中关闭,我将不得不在for-loop内再次创建。能不能指出我正确的方向。

1 个答案:

答案 0 :(得分:2)

正如我对Extract pdf page and insert into existing pdf的回答中所述,使用PdfStamper只是满足您要求的一种方式。如果您需要操作单个PDF文档PdfStamper可能是您的最佳选择,并且可以从另一个PDF 添加单个页面 >正如我之前的回答所示。

但是,您现在指出必须连接多个PDF文件。在这种情况下,使用PdfStamper不是最佳选择。您应该考虑切换到PdfCopy

假设您有以下文件。

String[] paths = new String[]{
    "resources/to_be_inserted_1.pdf",
    "resources/to_be_inserted_2.pdf",
    "resources/to_be_inserted_3.pdf"
};

您需要在包含路径"resources/main_document.pdf"的现有PDF的开头插入每个文档的第一页(并且只显示第一页),然后您可以执行以下操作:

Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(dest));
document.open();
PdfReader reader;
for (String path : paths) {
    reader = new PdfReader(path);
    copy.addPage(copy.getImportedPage(reader, 1));
    reader.close();
}
reader = new PdfReader("resources/main_document.pdf");
copy.addDocument(reader);
reader.close();
document.close();

如您所见,addPage()方法添加了单个页面,而addDocument()方法添加了文档的所有页面。

<强>更新

您似乎不希望插入新页面,但是您想要叠加页面:您希望在的基础上添加 / em>或 现有内容。

在这种情况下,你确实需要PdfStamper,但是你犯了两个关键错误。

  1. 关闭循环内的stamper。关闭stamper后,它将关闭:您无法再向其中添加任何内容。您需要将stamper.close()移出循环。
  2. 您关闭了循环中的reader,但stamper尚未释放 reader。您应首先免费读者。
  3. 这显示在SuperImpose示例中:

    public static final String SRC = "resources/pdfs/primes.pdf";
    public static final String[] EXTRA =
        {"resources/pdfs/hello.pdf", "resources/pdfs/base_url.pdf", "resources/pdfs/state.pdf"};
    public static final String DEST = "results/stamper/primes_superimpose.pdf";
    
    PdfReader reader = new PdfReader(SRC);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(DEST));
    PdfContentByte canvas = stamper.getUnderContent(1);
    PdfReader r;
    PdfImportedPage page;
    for (String path : EXTRA) {
        r = new PdfReader(path);
        page = stamper.getImportedPage(r, 1);
        canvas.addTemplate(page, 0, 0);
        stamper.getWriter().freeReader(r);
        r.close();
    }
    stamper.close();
    

    在这种情况下,我总是将导入的页面添加到主文档的第1页。如果要将导入的页面添加到不同的页面,则需要在循环内创建canvas对象。