I am using WeasyPrint to generate PDF in Django. I can generate pdf from a static html file like below -
from django.template import Context, Template
import weasyprint
with open('static_file.html', 'r') as myfile:
html_str = myfile.read()
template = Template(html_message)
context = Context({'some_key': 'some_value'})
rendered_str = template.render(context)
weasyprint.HTML(string=rendered_str).write_pdf('generated.pdf')
But I want to generate a PDF in which, I can include a common header/footer in each page and add pagination.
Also it will be very helpful if anyone can tell how to include a custom font to generate the PDF. I have installed the font in the OS (Ubuntu 14.04) but it is not working.
I have searched a lot on the web about these. But could not find a proper solution.
Since Weasyprint supports CSS Paged Media Module Level 3, simple headers and footers (e.g. pagination, like you mentioned) can be accomplished using CSS:
@page {
@top-right{
content: "Page " counter(page) " of " counter(pages);
}
}
Make sure you include your stylesheets when rendering:
HTML(string=rendered_html,
base_url=settings.SITE_URL).write_pdf(stylesheets=[CSS(settings.STATIC_ROOT + '/css/pdf_render.css')])
However, getting more complex headers/footers to render can be more.. complex. Some people have suggested the method of including a div element in the header that renders only for print (but I must admit I have only been able to get simple elements to render properly with this method):
@page {
@top-left {
content: element(pageHeader);
}
}
@media print {
#divHeader{
position: running(pageHeader);
}
}
There is also another method using fixed positions, as demonstrated in this gist: https://gist.github.com/pikhovkin/5642563
Currently running elements are not supported by WeasyPrint. Nevertheless I found a way to achieve the same result using named strings:
@page {
@top-center {
content: string(title);
}
}
header {
width: 0;
height: 0;
visibility: hidden;
string-set: title content();
}
Now you can add your content to an invisible HTML header element.
<header>Content of the header goes here</header>
I could get this to work simply by using position: fixed
for the header and footer.
First, as an element in fixed position does not occupy space on the page, you have to take into account for it by giving appropriate margins on the page, e.g.:
@page {
margin: 5cm 0 3cm 0;
size: A4;
}
then simply position the header and footer with respect to this margin:
header, footer {
position: fixed;
left: 0;
right: 0;
}
header {
/* subtract @page margin */
top: 5cm;
height: 5cm
}
footer {
/* subtract @page margin */
bottom: 3cm;
height: 3cm;
}
With this you can just put arbitrary HTML in <header>
and <footer>
elements and they will be repeated on every page.
Page counters do not seem to work there though, so you will need to implement them based @page
rules as described in the other answers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With