简体   繁体   中英

iText pdf Multiple Pages with same Content

How can i generate pdf report of multiple pages with same content on each page. Following is the code for single page report. Multiple pages should be in a single pdf file.

<%
    response.setContentType( "application/pdf" );
    response.setHeader ("Content-Disposition","attachment;filename=TEST1.pdf");

    Document document=new Document(PageSize.A4,25,25,35,0);
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    PdfWriter writer=PdfWriter.getInstance( document, buffer);
    document.open();
    Font fontnormalbold = FontFactory.getFont("Arial", 10, Font.BOLD);
    Paragraph p1=new Paragraph("",fontnormalbold);
    float[] iwidth = {1f,1f,1f,1f,1f,1f,1f,1f};
    float[] iwidth1 = {1f};

    PdfPTable table1 = new PdfPTable(iwidth); 
    table1.setWidthPercentage(100);
    PdfPCell cell =     new PdfPCell(new Paragraph("Testing Page",fontnormalbold));
    cell.setHorizontalAlignment(1);
    cell.setColspan(8);
    cell.setPadding(5.0f);
    table1.addCell(cell);

    PdfPTable outerTable = new PdfPTable(iwidth1); 
    outerTable.setWidthPercentage(100);

    PdfPCell containerCell = new PdfPCell(); 
    containerCell.addElement(table1); 
    outerTable.addCell(containerCell); 
    p1.add(outerTable);

    document.add(new Paragraph(p1));

    document.close();
    DataOutput output = new DataOutputStream( response.getOutputStream() );
    byte[] bytes = buffer.toByteArray();
    response.setContentLength(bytes.length);
    for( int i = 0; i < bytes.length; i++ ) { output.writeByte( bytes[i] ); }
    response.getOutputStream().flush(); 
    response.getOutputStream().close();
%>

There are different way to solve this problem. Not all of the solutions are elegant.

Approach 1: add the same table many times.

I see that you are creating a PdfPTable object named outerTable . I'm going to ignore the silly things you do with this table (eg why are you adding this table to a Paragraph? Why are you adding a single cell with colspan 8 to a table with 8 columns? Why are you nesting this table into a table with a single column? All of these shenanigans are really weird), but having that outertable , you could do this:

for (int i = 0; i < x; i++) {
    document.add(outerTable);
    document.newPage();
}

This will add the table x times and it will start a new page for every table. This is also what the people in the comments advised you, and although the code looks really elegant, it doesn't result in an elegant PDF. That is: if you were my employee, I'd fire you if you did this.

Why? Because adding a table requires CPU and you are using x times the CPU you need. Moreover, with every table you create, you create new content streams. The same content will be added x times to your document. Your PDF will be about x times bigger than it should be.

Why would this be a reason to fire a developer? Because applications like this usually live in the cloud. In the cloud, one usually pays for CPU and bandwidth. A developer who writes code that requires a multiple of CPU and bandwidth, causes a cost that is unacceptable. In many cases, it is more cost-efficient to fire bad developers, hire slightly more expensive developers and buy slightly more expensive software, and then save plenty of money on the long term thanks to code that is more efficient in terms of CPU and band-width.

Approach 2: add the table to a PdfTemplate , reuse the PdfTemplate .

Please take a look at my answer to the StackOverflow question How to resize a PdfPTable to fit the page?

In this example, I create a PdfPTable named table . I know how wide I want the table to be ( PageSize.A4.getWidth() ), but I don't know in advance how high it will be. So I lock the width, I add the cells I need to add, and then I can calculate the height of the table like this: table.getTotalHeight() .

I create a PdfTemplate that is exactly as big as the table:

PdfContentByte canvas = writer.getDirectContent();
PdfTemplate template = canvas.createTemplate(
    table.getTotalWidth(), table.getTotalHeight());

I now add the table to this template:

table.writeSelectedRows(0, -1, 0, table.getTotalHeight(), template);

I wrap the table inside an Image object. This doesn't mean we're rasterizing the table, all text and lines are preserved as vector-data.

Image img = Image.getInstance(template);

I scale the img so that it fits the page size I have in mind:

img.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());

Now I position the table vertically in the middle.

img.setAbsolutePosition(
    0, (PageSize.A4.getHeight() - table.getTotalHeight()) / 2);

If you want to add the table multiple times, this is how you'd do it:

for (int i = 0; i < x; i++) {
    document.add(img);
    document.newPage();
}

What is the difference with Approach 1? Well, by using PdfTemplate , you are creating a Form XObject . A Form XObject is a content stream that is external to the page stream. A Form XObject is stored in the PDF file only once, and it can be reused many times, eg on every page of a document.

Approach 3: create a PDF document with a single page; concatenate the file many times

You are creating your PDF in memory. The PDF is stored in the buffer object. You could read this PDF using PdfReader like this:

PdfReader reader = new PdfReader(buffer.toByteArray());

Then you reuse this content like this:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document doc = new Document();
PdfSmartCopy copy = new PdfSmartCopy(doc, baos);
doc.open();
for (int i = 0; i < x; i++) {
    copy.addDocument(reader);
}
doc.close();
reader.close();

Now you can send the bytes stored in baos to the OutputStream of your response object. Make sure that you use PdfSmartCopy instead of PdfCopy . PdfCopy just copies the pages AS-IS without checking if there is redundant information. The result is a bloated PDF similar to the one you'd get if you'd use Approach 1. PdfSmartCopy looks at the bytes of the content streams and will detect that you're adding the same page over and over again. That page will be reused the same way as is done in Approach 2.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM