ralfstuckert/pdfbox-layout

how to automatically create header and footer area when finishing a pdf page?

Closed this issue · 9 comments

Hi there!

When I finish a page and use ControlElement.NEWPAGE oder finally the last page is going to be rendered, how can I set header and footer areas?
I have to switch from iText to a different library and pdfbox-layout has done fine up to now (even with some tricky column layout to build table-like structures). iText uses event-handling to add headers and footers.
Maybe something similar exists in pdfbox-layout? Maybe with a DrawListener or RenderListener?

any help would be greatly appreciated!

ok, found a hint in listener.pdf

but I got a different question ...
I'd like to add a watermark picture, preferably when using the renderlistener's afterPage method.
But all I get is a

Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859) at rst.pdfbox.layout.elements.Document.render(Document.java:284)

You seem to change the (PDFLayout-)document's content during rendering. Could you provide a code sinppet?

Hello Ralf, it seems, that I have tried to add some rendering stuff at too many places/sources. I think I have to remove all but one and look, if it I get some result ...

Now I use a RenderListener and the .afterPage method. This works fine, when a page is finished, the method is called and all the stuff (header, footer, ...) is done.
BUT ... now I get a "Cannot read while there is an open stream writer" message when saving the document.

I can track it down to this:
I have implemented a RenderListener with the "finishing stuff" like headers and footers.
The methods beforePage and afterPage are called from the base class of all page defining classes.
In that base class a RenderContext is created:

private RenderContext getRenderContext() throws IOException {
		if (rc == null) {
			rc = new RenderContext(doc, doc.getPDDocument());
		}
		return rc;
	}

With getRenderContext() I run the beforePage and afterPage methods.
In this part, some stream is opened and never closed, so doc.save complains about it.
If I do not use the RenderContext, no error mesage comes up and the PDF is created.
When it is used, no PDF is created and the error is shown.

Is there anything I have to do with the RenderContext when closing/saving the document?

I tried to avoid this problem and set header and footer within the page-writing classes ... but this leads to pagenumber 0 and (because there are some classes that do write onto several pages but only one) some sections of the pdf nave a header/footer just on the last page of the section.
This is no workaround. I have to do it via listeners.
But how do I overcome the problems above?

You may only do low-level rendering stuff in the RendererListener as shown in the listener example. You must neither alter the Document or create your own RenderContext, since it opens and maintains a PDPageContentStream.

Could you provide a simplified example reproducing the problem?

Mmmh, to use my RenderListener, I have to call the afterPage method ... with what renderContext?
Where do I get it from.
Maybe the problem is, that I use a new RenderContext:
when ending a text section in the pdf I call

	protected void teardownWrite() throws PdfCException {
		try {
			// Kopf- und Fußzeile schreiben
			getEvent().afterPage(getRenderContext());
		} catch (IOException e) {
			throw new PdfCException(e);
		}
	}
	private RenderContext rc; 
	private RenderContext getRenderContext() throws IOException {
		if (rc == null) {
			rc = new RenderContext(myController.getDocument(), myController.getPDDocument());
		}
		return rc;
	}
	
	private PdfEvent getEvent() throws PdfCException {
		if (event == null) {
			event = new PdfEvent(myController, myData, myController.getZeichensatz());
		}
		return event;
	}

with

public class PdfEvent implements RenderListener {
...
}

If the "new RenderContext(...)" is the problem, wherer do I get it from for the afterPage method?

OOps, it may be told, that I tried to call afterPage() manually ...
removing this, the method is called later automatically ... now I try to make it work as it should.

Thanks for giving the hints I needed!

Finally ... done (needed a renderer as well as a renderListener)
Thanks for your help!