iText

Why does my header overlap with my content?

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:

Java
protected void createPdf(String dest) throws Exception {
  PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
  Document doc = new Document(pdfDoc);

  TableHeaderEventHandler handler = new TableHeaderEventHandler(doc);
  pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler);

  // Calculate top margin to be sure that the table will fit the margin.
  float topMargin = 20 + handler.getTableHeight();
  doc.setMargins(topMargin, 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:

Java
    pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler);

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

Java
public class TableHeaderEventHandler extends AbstractPdfDocumentEventHandler {

  private Table table;
  private final float tableHeight;
  private final Document doc;

  public TableHeaderEventHandler(Document doc) {
    this.doc = doc;
    initTable();

    TableRenderer renderer = (TableRenderer) table.createRendererSubTree();
    renderer.setParent(new DocumentRenderer(doc));

    LayoutResult result = renderer.layout(
      new LayoutContext(new LayoutArea(0, PageSize.A4))
    );

    tableHeight = result.getOccupiedArea().getBBox().getHeight();
  }

  @Override
  public void onAcceptedEvent(AbstractPdfDocumentEvent currentEvent) {
    PdfDocumentEvent docEvent = (PdfDocumentEvent) currentEvent;
    PdfDocument pdfDoc = docEvent.getDocument();
    PdfPage page = docEvent.getPage();

    PdfCanvas canvas = new PdfCanvas(
      page.newContentStreamBefore(),
      page.getResources(),
      pdfDoc
    );

    PageSize pageSize = pdfDoc.getDefaultPageSize();

    float coordX = pageSize.getX() + doc.getLeftMargin();
    float coordY = pageSize.getTop() - doc.getTopMargin();
    float width = pageSize.getWidth() - doc.getLeftMargin() - doc.getRightMargin();
    float height = getTableHeight();

    Rectangle rect = new Rectangle(coordX, coordY, width, height);

    new Canvas(canvas, rect)
      .add(table)
      .close();
  }

  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:

Java
float topMargin = 20 + handler.getTableHeight();
doc.setMargins(topMargin, 36, 36, 36);

The result looks like this:

https://itextpdf.com/sites/default/files/t5RSy.png
https://itextpdf.com/sites/default/files/t6sqU.png

Now the content does not overlap the header.

Click Why does my header overlap with my content? - iText 5 PDF Library Explained if you want to see how to answer this question in iText 5.