简体   繁体   English

iText pdf具有相同内容的多个页面

[英]iText pdf Multiple Pages with same Content

How can i generate pdf report of multiple pages with same content on each page. 我如何生成多页的pdf报告,每页内容相同。 Following is the code for single page report. 以下是单页报告的代码。 Multiple pages should be in a single pdf file. 多页应放在一个pdf文件中。

<%
    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. 方法1:多次添加同一张表。

I see that you are creating a PdfPTable object named outerTable . 我看到您正在创建一个名为outerTablePdfPTable对象。 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: 我将忽略您对该表所做的愚蠢的事情(例如, 为什么要将此表添加到“段落”中?为什么要将具有colspan 8的单个单元格添加到具有8列的表中呢?为什么要将此表嵌套到一个带有单列的表?所有这些outertable确实很怪异),但是有了这个outertable ,您可以这样做:

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. 这将添加表x次,并将为每个表启动一个新页面。 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. 注释中的人也建议您这样做,尽管该代码看起来确实很优雅,但它不会产生优雅的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. 因为添加表需要CPU,而您使用的CPU是所需CPU的x倍。 Moreover, with every table you create, you create new content streams. 此外,对于您创建的每个表,您都将创建新的内容流。 The same content will be added x times to your document. 相同的内容将x次添加到您的文档中。 Your PDF will be about x times bigger than it should be. 您的PDF大约应该是它的x倍。

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. 在云中,通常需要为CPU和带宽付费。 A developer who writes code that requires a multiple of CPU and bandwidth, causes a cost that is unacceptable. 编写需要占用大量CPU和带宽的代码的开发人员,所付出的代价是不可接受的。 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. 在许多情况下,解雇糟糕的开发人员,聘请价格稍高的开发人员并购买价格稍高的软件,然后从长期来看,可以节省大量资金,这要归功于代码,这些代码在CPU和频段方面的效率更高,从而更具成本效益。 -宽度。

Approach 2: add the table to a PdfTemplate , reuse the PdfTemplate . 方法2:将表格添加到PdfTemplate ,重用PdfTemplate

Please take a look at my answer to the StackOverflow question How to resize a PdfPTable to fit the page? 请看一下我对StackOverflow问题的回答如何调整PdfPTable的大小以适合页面?

In this example, I create a PdfPTable named table . 在此示例中,我创建了一个PdfPTable命名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. 我知道我希望表格有多大( PageSize.A4.getWidth() ),但我事先不知道它将有多高。 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() . 因此,我锁定了宽度,添加了需要添加的单元格,然后可以像这样计算表格的高度: table.getTotalHeight()

I create a PdfTemplate that is exactly as big as the table: 我创建一个与表一样大的PdfTemplate

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

I now add the table to this template: 我现在将table添加到此模板:

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

I wrap the table inside an Image object. 我将table包装在Image对象中。 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 ,以使其适合我所想到的页面大小:

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? 方法1有什么区别? Well, by using PdfTemplate , you are creating a Form XObject . 好吧,通过使用PdfTemplate ,您可以创建一个Form XObject A Form XObject is a content stream that is external to the page stream. 表单XObject是页面流外部的内容流。 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. 表单XObject仅在PDF文件中存储一次,并且可以多次重复使用,例如在文档的每一页上。

Approach 3: create a PDF document with a single page; 方法3:用一页创建PDF文档; concatenate the file many times 多次连接文件

You are creating your PDF in memory. 您正在内存中创建PDF。 The PDF is stored in the buffer object. PDF存储在buffer对象中。 You could read this PDF using PdfReader like this: 您可以像这样使用PdfReader阅读此PDF:

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. 现在,你可以把存储在字节baosOutputStream您的response对象。 Make sure that you use PdfSmartCopy instead of PdfCopy . 确保使用PdfSmartCopy而不是PdfCopy PdfCopy just copies the pages AS-IS without checking if there is redundant information. PdfCopy仅按原样复制页面,而不检查是否存在冗余信息。 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. 结果是一个PDF肿的PDF,类似于使用方法1时将得到的PdfSmartCopy查看内容流的字节,并会检测到您一次又一次地添加同一页面。 That page will be reused the same way as is done in Approach 2. 该页面将以与方法2中相同的方式重复使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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