Why does my header overlap with my content?

Category: 
Tags: headeriText 7

I am using page events to create a header that consists of a table. This table is added to each page in my document, but unfortunately, it overlaps with the rest of my content. How can I avoid this?

Question inspired by the posts on StackOverflow dated February 17, 2016 by Abhimanyu Katoch and Herin

Please take a look at the TableHeader example adapted for iText 7.

In this example, I create a document with some "Hello World" content:

public void createPdf(String dest) throws IOException {
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
    Document doc = new Document(pdfDoc, PageSize.A4);
    TableHeaderEventHandler handler = new TableHeaderEventHandler(doc);
    pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler);
    doc.setMargins(20 + handler.getTableHeight(), 36, 36, 36);
    for (int i = 0; i < 50; i++) {
        doc.add(new Paragraph("Hello World!"));
    }
    doc.add(new AreaBreak());
    doc.add(new Paragraph("Hello World!"));
    doc.add(new AreaBreak());
    doc.add(new Paragraph("Hello World!"));
 
    doc.close();
}

As you can see, I also define a TableHeaderEventHandler. I use this event as a page event:

pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler);

What does this mean? Let's take a look at the implementation of this event handler:

public class TableHeaderEventHandler implements IEventHandler {
     protected Table table;
     protected float tableHeight;
     protected Document doc;
 
     public TableHeaderEventHandler(Document doc) {
         this.doc = doc;
         table = new Table(1);
         table.setWidth(doc.getPdfDocument().getDefaultPageSize().getRight() - doc.getPdfDocument().getDefaultPageSize().getLeft() - doc.getLeftMargin() - doc.getRightMargin());
         table.addCell("Header row 1");
         table.addCell("Header row 2");
         table.addCell("Header row 3");
         TableRenderer renderer = (TableRenderer) table.createRendererSubTree();
         renderer.setParent(new Document(new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))).getRenderer());
         tableHeight = renderer.layout(new LayoutContext(new LayoutArea(0, PageSize.A4))).getOccupiedArea().getBBox().getHeight();
     }
 
     @Override
     public void handleEvent(Event event) {
         PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
         PdfDocument pdfDoc = docEvent.getDocument();
         PdfPage page = docEvent.getPage();
         PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
         Rectangle rect = new Rectangle(pdfDoc.getDefaultPageSize().getX() + doc.getLeftMargin(),
                 pdfDoc.getDefaultPageSize().getTop() - doc.getTopMargin(), 100, getTableHeight());
         new Canvas(canvas, pdfDoc, rect)
                 .add(table);
     }
 
     public float getTableHeight() {
         return tableHeight;
     }
 }

You need the height of the table to set the right top margin for the document. When you create a TableHeaderEventHandler, the height of the rendered table is calculated in the constructor using layout() method. According to this value you will use this line:

doc.setMargins(20 + handler.getTableHeight(), 36, 36, 36);

The result looks like this:

Header table and content: no overlap. Page 1.
Header table and content: no overlap. Page 1.
Header table and content: no overlap. Page 2.
Header table and content: no overlap. Page 2.

Now the content does not overlap the header.

Click this link if you want to see how to answer this question in iText 5.