Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] How to generate a single page PDF with dynamic height? #1154

Open
FilipeMarch opened this issue May 2, 2024 · 8 comments
Open

Comments

@FilipeMarch
Copy link

FilipeMarch commented May 2, 2024

Hello, I'm trying to print some pdfs using a thermal printer (58mm) on my mobile app.

from fpdf import FPDF

pdf = FPDF("P", "mm", (135, "What do I put here?"))

The issue is that the pdf page is generated dynamically from the data of each user. We generate an image that I don't know beforehand what's gonna be the final height.

So the page can have a final height of 100, 300, 1200 pixels, I simply do not know.

I want to generate a single page pdf that will grow until it fits all the content. The main issue for me is making sure that all the content is going to fit in a single page.

I know that 135 is the correct width, but because the height is dynamic, how can I deal with that situation?

I would appreciate any help or guidance on how to approach this, thanks!

@gmischler
Copy link
Collaborator

This is essentially the same scenario as described in #678.
The general approach I suggested there is likely to work for you as well.

@FilipeMarch
Copy link
Author

FilipeMarch commented May 9, 2024

This is essentially the same scenario as described in #678. The general approach I suggested there is likely to work for you as well.

I don't see how your example at #678 (comment) can solve this issue. You created three pages, changed the dimension of the second and third page, and rotated the third page.

How does that relate to dynamically changing the height of a single page based on content?

Look at this very simple example:

from fpdf import FPDF

pdf = FPDF()
pdf.set_font('Courier', '', 11)
pdf.add_page()

x = 200
for i in range(x):
    pdf.cell(txt=f'{i:02}: a'*5, new_x="LEFT", new_y="NEXT")

doc = pdf.output('pagesizetest.pdf')

Would you be able to change that code above such that it will result in a pdf containing only one single page with the whole text and no space left? This is the output I'm expecting:

image

pagesizetest.pdf

I want the result to always fit in one single page. The width of the page needs to be 135, the height depends on the size of the content, which I can't predict. The content may have text and images.

@andersonhc
Copy link
Collaborator

andersonhc commented May 9, 2024

The code below is taking your example and applying the approach taken on #678 to adjust the page size:

from fpdf import FPDF

pdf = FPDF("P", "mm", (135, 999999))
pdf.set_font('Courier', '', 11)
pdf.add_page()
with pdf.rotation(180, x=pdf.w/2, y=pdf.h/2):
    x = 500
    for i in range(x):
        pdf.cell(text=f'{i:02}: a'*5, new_x="LEFT", new_y="NEXT")

pdf.pages[1].set_dimensions(pdf.w_pt, (pdf.y + pdf.t_margin)*pdf.k)

doc = pdf.output('pagesizetest.pdf')

The PDF standard interprets the vertical coordinates from bottom to top, so when you re-dimension your page you lose the content at the top - that's why rotating the content will make your life a lot easier. As your use case is to print the result I believe it shouldn't be an issue.

@FilipeMarch
Copy link
Author

Woooow, it works! That's awesome. Thanks @andersonhc and @gmischler, I'm really glad this workaround exists, that was quite unexpected.

Later I will see if I can rotate the pdf 180 degrees again after the whole process, because we are printing all other receipts in the "normal" orientation, it would be strange if only this receipt had a different behavior.

@gmischler
Copy link
Collaborator

Later I will see if I can rotate the pdf 180 degrees again after the whole process,

I thought about that quite a bit, and couldn't figure out a really good way yet.
Given how fpdf2 is organized internally, you need to know the pivot point of a rotation in advance.

There might be a (very hacky) way to do two nested rotations around the original center and later replace the pivot coordinates of the outer one in the output data stream.

But the easiest way will be to do some postprocessing with another tool.
Right next door in the same organisation for example we have pypdf, which has no problem at all to rotate a page.

@Lucas-C
Copy link
Member

Lucas-C commented May 24, 2024

Do you have other questions regarding this @FilipeMarch? Or can we close this issue?

@gmischler & @andersonhc: do you think that we should document this workaround in our documentation?

@FilipeMarch
Copy link
Author

Do you have other questions regarding this @FilipeMarch? Or can we close this issue?

@gmischler & @andersonhc: do you think that we should document this workaround in our documentation?

Hello, I ended up finding a solution to print the image directly on the thermal printer, without having to create a pdf first containing the image, which made the whole process much faster.

I really would like this library to support dynamic height without the side-effect of ending up with the content rotated, and needing another library to fix it. The whole concept is strange, and on the other hand I believe creating a pdf with dynamic height is very common in general.

Thanks for the help and support, this issue can be closed.

@Lucas-C
Copy link
Member

Lucas-C commented May 24, 2024

Thank you for the feedback @FilipeMarch! 👍

I have to say that I am a bit hesitant about this: do we want to support this feature in fpdf2?
What do you think about this @andersonhc & @gmischler?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants