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: 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

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

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.

Architecture

Python. Of course.

Let’s open the box. The engine is of course in Python. HTML is parsed with lxml, CSS with tinycss.
The cascade (C in CSS) handles selectors and rule priorities. The render tree is made of rectangular boxes. The layout splits them across lines and pages; and gives them their position and size.
We then paint on a cairo surface, with Pango handling the text.
Priority: ease of implementation over runtime speed, but we still fix obvious performance problems.

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

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!