2
votes

I am stamping a PDF form over and over using iText and trying to compile the resulting single page pdfs into a single pdf with many pages in RAM and return it in an http response. An invalid PDF comes out no matter what I do. If I do the same thing without the copy for a single page the PDF is perfect. I've tried using PdfSmartCopy and PdfCopy, but the result is always invalid. I think I am doing everything just as shown on the examples on the internet, but I must be missing something. Thanks for your suggestions!

ByteArrayOutputStream mainBaos;
PdfReader reader;
PdfStamper stamp;
AcroFields form;

OutputStream out = null;
try
{
    List<PrintableCheck> checks = service.getChecksToPrint();

    mainBaos = new ByteArrayOutputStream();
    Document doc = new Document();
    PdfSmartCopy mainPDF = new PdfSmartCopy(doc, mainBaos);
    doc.open();

    for (PrintableCheck check : checks)
    {
        reader = new PdfReader(PDF_FILENAME);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        stamp = new PdfStamper(reader, baos);

        form = stamp.getAcroFields();

        form.setField("checkDate", check.getDate());
        form.setField("checkNumber", check.getNumber());
        form.setField("amountAlpha", check.getAmountAlpha());
        form.setField("amount", check.getAmount());

...

        stamp.setFormFlattening(true);
        stamp.close();
        reader.close();

        PdfReader reader2 = new PdfReader(baos.toByteArray());
        PdfImportedPage page = mainPDF.getImportedPage(reader2, 1);
        mainPDF.addPage(page);
        mainPDF.freeReader(reader2);
        reader2.close();
    }

    response.setContentType("application/pdf");
    response.setContentLength(mainBaos.size());
    response.setHeader("Expires", "0");
    response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
    response.setHeader("Pragma", "public");
    response.addHeader("Content-Description", "File Transfer");
    response.addHeader("Content-Disposition", "attachment; filename=checks"
        + bank + "-" + DATE_FORMAT.format(new Date()) + ".pdf");
    response.addHeader("Content-Transfer-Encoding", "binary");
    out = response.getOutputStream();
    doc.close();
    mainBaos.writeTo(out);
    out.flush();
}
catch (Exception e)
{
    log.error("Failed to print checks", e);
}
finally
{
    if (out != null)
    {
        try
        {
            out.close();
        }
        catch (IOException e)
        {
            log.error("Could not close output stream", e);
        }
    }
}
1

1 Answers

2
votes

Take a look at the following line:

response.setContentLength(mainBaos.size());

You tell the response how many bytes you will send to the browser. However: at that moment, you don't know the exact size of the PDF, because you haven't closed the document yet.

You can solve your problem by moving the following line up:

doc.close();

This finalizes the document. Do not set the content length before this line.