WeasyPrint

CSS → PDF
New CSS engine (like WebKit, Gecko), renders PDF
Been at Kozea working on it for ~1.5 years now.
PDF
Hi-Fi documents for printing, archiving, …
How to generate them dynamically?
Best document format for many use cases
Invoices, expert reports, business cards, …
Flask
from flask_weasyprint import render_pdf
from flask import Flask
app = Flask(__name__)
@app.route("/hello")
def hello():
return "Hello World!"
@app.route("/hello.pdf")
def hello_pdf():
return render_pdf("/hello")
You know Flask.
Nice micro-framework for making Python web apps.
Tools to generate beautiful HTML/CSS/SVG documents.
What about PDF?
Flask-WeasyPrint (demo)
from flask_weasyprint import render_pdf
from flask import Flask
app = Flask(__name__)
@app.route("/hello")
def hello():
return "Hello World!"
@app.route("/hello.pdf")
def hello_pdf():
return render_pdf("/hello")
Once you have that, PDF is easy.
WeasyPrint: like the print function of your browser, but with
a layout engine designed for print.
Fetching a dynamic image: data flow
- WeasyPrint
- WeasyPrint → HTTP / network → WSGI → Flask
- Flask-WeasyPrint
- WeasyPrint → WSGI → Flask
Flask-WeasyPrint: optimization only. Shortcuts the network and
stays within one Python thread/process.
It’s standard WSGI: easy to adapt to other framework.
(The WSGI client is Flask’s test client.)
Generating PDF
- LaTeX
- ReportLab
- LibreOffice
- wkhtml2pdf (WebKit)
- PrinceXML
LaTeX: weak reproducibility, inflexible stylesheets
ReportLab open-source: imperative, no vector graphics
LibreOffice: heavyweight, results not great
WebKit: weak support for Paged Media, average font rendering,
hard to patch/fork
PrinceXML: expensive, not open-source. But our most serious competitor.
NIH
- 2011-04: Let’s build a browser engine!
- 2011-10: v0.1
- 2012-02: v0.6, stable API
- Today: v0.14
- Soon®: v1.0
0.14 is very stable already. There are only a few details I want
to take care of before calling it 1.0.
Features
weasyprint.org/features
Raster and vector (SVG) images, PDF bookmarks, hyperlinks
CSS 2.1: 95%*
CSS 3: selectors, colors, 2D transforms, paged media
SVG images are rendered as vectors in the PDF output.
Nothing scientific in the 95% figure, just a guesstimate.
Paged media: fine page-break control, page-margin boxes
(headers and footers, automatic numbering)
No @font-face, but can use any installed font.
Examples
PyConFR 2012 schedule
CSS 2.1 intro
Acid2

Schedule: from the website + a custom stylesheet.
CSS intro: Internal and external hyperlinks, bookmarks, page numbers,
2D transforms
Acid2: this is WeasyPrint’s PNG output.
Using WeasyPrint
- HTML & CSS in, PDF or PNG out
- Docs
- Command-line API
- Python API
See the docs for details. URLs, filenames, file objects, strings.
In Python, fine control on fetching of external resources.
CSS for Paged Media
h1 { page-break-before: right }
h1, h2, h3 {
page-break-after: avoid }
@page { size: A4 landscape;
margin: 2cm }
@page :left { @bottom-right {
content: counter(page) } }
@media print { nav { display: none } }
Keyword for finding docs: CSS Paged Media.
Some properties control page breaks,
@page for the page and its headers/footers,
@media for conditinals.
Units: 96 CSS px / CSS inch, for historical reasons.
px may not match device pixels. Meaningless in print
anyway, use cm, mm, pt, etc.
CSS box model…
It’s complicated.
No need to read this in details.
The CSS 2.1 spec has dozen of pages describing this in details.
I had to read it many times, with a pen and paper. This is
what I got after many iterations.
import weasyprint
- 7500 lines code + 8200 of tests
- Python 2.6+ and 3.x
- BSD license
In spite of CSS’s inherent complexity, we try to keep the engine
simple. (Especially compared to a Gecko or a WebKit.)
Python 2 & 3 with the same code base. Not using
six,
but a custom 100-lines compat.py file.
It’s open source and free software.
Thanks.
Questions?
Come and chat with us!