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!