Hi. I've been using fpdf2 for a while now, it works great and I'd like to contribute some changes I've made that may be useful to others.
I usually need to avoid page breaks in some parts that uses a lot of unbreakable incompatible methods like get_y(), etc. What I usually do is equivalent (I wrap this in a context manager) to:
with pdf.offset_rendering() as dummy:
funny_function(dummy)
if dummy.page_break_triggered:
pdf.add_page()
funny_function(pdf)
...
where funny_function encapsulates the functions that are not compatible with unbreakable.
As noted in the docs, this can be memory-demanding if the document is large. In my use case it is also unnecessary slow: most of the times no page break is triggered, yet it is necessary to run funny_function twice, and the memory management of the PDFRecorder used by the context manager takes some time.
I gained a lot of efficiency creating an alternative trimmed recorder that uses less memory and has almost zero overhead in the case that no page break has been triggered. I had no problems in my use case (just plain text and lines added inside the context), but I assume it can break things in some cases.
The difference with PDFRecorder, is that instead of copying the whole pdf pages contents it just saves the position where the contents end to roll back. This is incompatible with closed FPDF objects where the page contents is a PDFContentStream instead of a bytearray (I was confused at first, as the docs state otherwise). If no page break as been triggered, nothing has to be done. If a page break has been triggered, restoring the the contents to the previous state is cheaper than with PDFRecorder. I guess something similar was originally planned with the context manager, as it has a accept_page_breaks parameter that does not seems to be used even if it has it own test.
I guess that the idea can be of value to add to the project, yet I am sure that there are many more things that must be taken into account. I can make a PR with the bare-bones structure so it's easier to evaluate the proposal. I tried to adapt PDFRecorder to my needs, but ended up with unnecessary complicated code just to avoid making a new class that serves for a similar yet different purpose.
Hi. I've been using fpdf2 for a while now, it works great and I'd like to contribute some changes I've made that may be useful to others.
I usually need to avoid page breaks in some parts that uses a lot of
unbreakableincompatible methods likeget_y(), etc. What I usually do is equivalent (I wrap this in a context manager) to:where
funny_functionencapsulates the functions that are not compatible withunbreakable.As noted in the docs, this can be memory-demanding if the document is large. In my use case it is also unnecessary slow: most of the times no page break is triggered, yet it is necessary to run
funny_functiontwice, and the memory management of thePDFRecorderused by the context manager takes some time.I gained a lot of efficiency creating an alternative trimmed recorder that uses less memory and has almost zero overhead in the case that no page break has been triggered. I had no problems in my use case (just plain text and lines added inside the context), but I assume it can break things in some cases.
The difference with
PDFRecorder, is that instead of copying the whole pdf pages contents it just saves the position where the contents end to roll back. This is incompatible with closedFPDFobjects where the page contents is aPDFContentStreaminstead of abytearray(I was confused at first, as the docs state otherwise). If no page break as been triggered, nothing has to be done. If a page break has been triggered, restoring the the contents to the previous state is cheaper than withPDFRecorder. I guess something similar was originally planned with the context manager, as it has aaccept_page_breaksparameter that does not seems to be used even if it has it own test.I guess that the idea can be of value to add to the project, yet I am sure that there are many more things that must be taken into account. I can make a PR with the bare-bones structure so it's easier to evaluate the proposal. I tried to adapt
PDFRecorderto my needs, but ended up with unnecessary complicated code just to avoid making a new class that serves for a similar yet different purpose.