Big differences between PDF page and preview/Print button page

After trying hard for several weeks, I finally managed to create a fully working pdf print format with pagination. However, the preview and “Print” result look totally different (endless paper view with no pagination at all).

Q1: Is there a way to make PDF and “Print” button result look 1:1 the same? If there is no way to make pdf and Print-button prints look the same, what’s their purpose then? Why not use just one instead of 2 different options with different layout? It may confuse end user and lead to incorrect printouts.

Q2: How to render Footer and Header within the “Print” button generated page?

Q3: Is there a way to display pagination in Print page too? (Working fine in pdf)

I’d be very happy to gain more insights into this topic - feel free to share additional resources or print designer examples which fulfill my needs (or parts of).

The difference is because PDFs are rendered using wkhtmltopdf which does not support latest CSS, whereas printing is based on how your browser renders the print format.

Why use PDF? Because wkhtmltopdf supports injecting headers, footers and page numbers whereas browsers can not tell how many pages your content will span (thus the endless paper preview).

How to achieve a similar layout on both PDF & Prints

  • Option 1: Use Print Designer, the most beginner friendly solution. However the designer is still in beta so there might be some bugs.

  • Option 2: Use Chrome Headless rendering for PDF (more on this below)

  • Option 3: Add vendor prefixes to your CSS (specially flex/grid) to make sure your current wkhtmltopdf can understand them. Search for online prefixing tools.

How to apply Headers, Footers & Page Numbering on Prints

  • Not very straightforward solution, but it can be done through Custom Print Formats, as explained below.

For more on this or to use Chrome Headless, refer to this

5 Likes

Another solution I use is to just stick with old-fashioned plain in-line CSS.

You can manage the padding of every element which should make both the prints similar.

1 Like

Wow, lots of information right here - some great references too. Thanks, didn’t expect such a response.

I will dig through everything and take my time. I’ll get back if there are further questions, otherwise happily mark it as resolved :slight_smile:

Unfortunately, I’m still facing problems. I tried already several things in the past and recently:

Default Print format builder

  • Very limited in design and content, therefore no real option.

Print designer:

  • Experiencing a lot of layout shifts and limitations in custom content/design, therefore no option too. Very promising though.

Chrome headless rendering:

  • Awesome approach for further use, but since I’m mostly struggling with preview/print and not PDF’s it’s not the solution here. Nor do header prefixes.

Current main problem (using custom print format):

Since print designer is no option, I’m searching for an option to create paginated Print preview/Prints which include header/footer with page enumeration. This seems impossible to me, therefore PDF seem to be the only solution. Is there no way of achieving this?

Please note, I’m trying to print dynamic content lengths (Article description) and need to rely on dynamic page breaks therefore. Approaches like putting 4 Articles per page and adding a page break won’t work.

I have already provided the solution, please check

Note on this: since page numbering involves some JavaScript, it’s better to open your print preview in web view / full page view before printing.

3 Likes

After taking a lot of time testing chrome headless, I’m still facing problems. It seems like there is no real and clean option, am I right?

My thoughts on chrome headless approach

It’s a kind of hacky way to achieve footer/header/content sections, even though I like the more up-to-date alternative. Even with the best HTML/CSS there is still a difference between browsers, which will lead to layout differences and therefore also issues with the pagination, which is unacceptable for me.
Additionally, the script doesn’t actually work without issues (Sorry, I appreciate it, but need to say): If there is a table row which is too large to fit onto the current page, there will be a forced page break by the browser. This will lead to additional space, which is not considered within the script AFAIK. A better solution will be:

let currentHeight = 0;
const maxHeight = pageHeight - headerHeight - footerHeight;
let pageCount = 1;
var tableRows = document.querySelectorAll('.print-body tr');
tableRows.forEach((row) => {
	let height = row.getBoundingClientRect().height;
	if (currentHeight + height > maxHeight) {
		pageCount++;
		currentHeight = 0;
	}
	currentHeight += height;
});

Also, the css is missing an:

.page-number{
    position: absolute;
}

So… is there no real option, which can generate header, footer, body without generating various layouts?

I’d rather like a pdf-preview only instead of html preview and pdf generation in parallel.

Regarding your first concern, generating a PDF with different browsers (using Chrome Headless) should produce consistent results since the PDF generation happens on the server where Chrome is installed.

As for page numbering, I never mentioned that it would produce 100% accurate results but it’s the closest you could achieve with few lines of code. Otherwise, your best bet would be Chrome Headless + Puppeteer / Pyppeteer.

First of all, thank you for your patience @Yamen_Zakhour - I really appreciate it.

My issue relies on the different layout from print button/preview to pdf. I’m aware thet the pdf will look the same every time, but the preview or print button-printout does differ, which bothers me. I guess this is a current limitation of erpnext (prbly no way around custom app).

In general, print views should be consistent across modern browsers. If needed, you can use CSS vendor prefixes for compatibility with older browsers.

For PDFs, since Chrome Headless handles the generation on the server, you’ll get consistent results across browsers. If there are small differences between the print view and the PDF, you might need to adjust things manually.

To add page numbers to your PDFs, you’ll need a custom solution. You could use Puppeteer or Pyppeteer on your server with Chrome Headless to manage PDF creation with page numbers.

However, it can be difficult, so a simpler approach would be using the above JavaScript then Print to PDF instead of generating PDF from server

Hey @Yamen_Zakhour
I think I’m slowly getting on track, but there are still some difficulties. After digging deeper for the last few days, I might have found the main cause for my struggle: I experienced a weird behavior of all browsers in case of header height > 250px… Firefox won’t print the header on the second page, chrome won’t even take the height property into account altogether.

This is a bummer… header height > 75mm (or 250px) is really needed here. I’ll keep looking for a solution, but it doesn’t look good so far. Is there any solution you might know?

Hey mate, not that I am aware of and I do not think that the solutions proposed in the below link are applicable (given that data rendered is dynamic). Test them out or you could try to restructure and redesign your headers to keep them below 250px.

I wondered about how fast you were able to provide a related report on SO :slight_smile: - unfortunately you were right, no real solution so far (at least not without a lot of JS).

I just wanted to give you and others a final update on my case: it turned out to be quite a long journey in order to get Print formats look the way I wanted. My final solution is as follows:

My final solution:

Those utilities aren’t public yet. If there is high demand, I might consider it, though.

  • Created custom Frappe app which will add a jinja function in order to pre-calculate HTML element’s height (based of css styles). This gives me maximum freedom to calculate page-breaks, page numbers e.g. in advance - even with mixed html contents (like for e.g. adding an image within a table row). This solution allows for html-to-pdf generation too without any third party app (like frappe-pdf).
  • Since playwright has a pretty bad cold-boot time, I’m using a standalone python app on my Server, which handles the calculation and pdf-generation stuff.

I did indeed try several other solutions, which might have saved some effort and time, but I wasn’t able to find any good option:

  • Trying to trick html into larger table headers: Very hacky approach which is quite limited since print-preview does still looks different.
  • Pre-calculate html element-size using python libraries like pillow: Not suitable with mixed html content - only possible for basic texts.
  • Weasyprint: Might have been an option, but with high costs. I noticed however, that Weasyprint is already part of Frappe, even if it isn’t widely used yet.

Thank you @Yamen_Zakhour for your support!

1 Like

Congratulations.

My humble suggestion. Release it in public domain, even if there is no demand.

After a couple of months, you will find many persons using it, and a few might improve it :wink:

Update: We just found the holy grail for better prints.

Split Print Format table automatically into pages based on rendered size.

Using our custom app’s jinja function, we are now able to split the table rows according to a given “max-size” per page, taking print format styles into account. You just pass the whole table html and will get a paginated version back. Easy as that.

We’re still finishing everything up and are planning to make it public. Might be our contribution to the frappe community :slight_smile: :fireworks: