WeasyPrint Documentation
repository·main·Indexed 27 days ago
https://github.com/kozea/weasyprintA Python-based visual rendering engine that converts HTML and CSS into high-quality PDF documents. It provides a command-line API and a Python library featuring classes like HTML, CSS, and Attachment for document generation. WeasyPrint supports advanced printing standards including PDF/A, PDF/UA, and PDF/X, as well as specialized formats like Factur-X/ZUGFeRD electronic invoices. Key features include support for CSS page selectors, named strings for headers/footers, automatic hyphenation, and PDF interactive elements like hyperlinks and forms.
What's inside WeasyPrint
- WeasyPrint is a visual rendering engine for HTML and CSS that exports to PDF. It is designed to support web standards for printing and is particularly useful for turning HTML pages into documents like statistical reports, invoices, and tickets. Unlike other engines, it does not use WebKit or Gecko; instead, it uses a CSS layout engine written in Python specifically designed for pagination.
Understand the WeasyPrint rendering pipeline
mainWeasyPrint follows a multi-step process to transform HTML and CSS into a PDF document, similar to how web browsers work:
- HTML Parsing: The HTML document is fetched and parsed into an element tree (similar to the DOM).
- CSS Parsing: CSS stylesheets are fetched and parsed.
- Style Application: Stylesheets are applied to the element tree.
- Formatting Structure: The styled tree is transformed into a formatting structure consisting of rectangular boxes.
- Layout: Boxes are laid out with fixed dimensions and positions onto pages (handling line breaks and page breaks).
- Stacking & Drawing: Boxes are re-ordered according to stacking rules (like
z-index) and drawn onto PDF pages. - Metadata: Document information, attachments, hyperlinks, and PDF trim/bleed boxes are added.
Quickstart with the WeasyPrint Python Library
mainYou can quickly render a URL to a PDF or apply inline stylesheets using the
HTMLandCSSclasses.Security Warning: Using WeasyPrint with untrusted HTML or untrusted CSS may lead to security problems.
from weasyprint import HTML HTML('https://weasyprint.org/').write_pdf('/tmp/weasyprint-website.pdf')Get professional support for WeasyPrint
mainIf you require rapid bug fixes, new feature development, or team training, you can access professional support from CourtBouillon. They offer direct contact via email or chat, as well as long-term consulting packages for priority support.Secure WeasyPrint when using untrusted HTML or CSS
mainWhen processing HTML, CSS, or SVG from untrusted sources, WeasyPrint is susceptible to security risks including high memory consumption, infinite rendering loops, and local file leaks.
To mitigate these risks, follow these best practices:
General Process Security
- Do not launch the service as root.
- Launch the process as a user with limited access to the filesystem, network, and memory.
- Use a container to isolate the rendering environment.
Mitigating Long Renderings and Infinite Loops
Specially crafted documents can cause high CPU/memory usage or infinite loops. To prevent this:
- Limit rendering time and memory use at the process level (e.g., using
evil-reload-on-asandharakiriin uWSGI, orulimiton Linux). - Automatically kill processes that exceed memory or time thresholds.
- Truncate and sanitize HTML and CSS input to limit document size and prevent access to external URLs.
Mitigating Infinite Network Requests
WeasyPrint can reach network resources via
https://orftp://URIs. While there is a default 10-second timeout for these protocols, they can still cause issues.- Use a custom URL fetcher to control network access.
- Note that the 10-second timeout does not apply to
file://URIs.
Mitigating Local File Access Leaks
WeasyPrint can access local files using
file://URIs (e.g., in<img>or<embed>tags), which can be exploited to leak sensitive files or cause infinite rendering (e.g., via/dev/urandom).- Restrict process access to trusted files using sandboxing.
- Use a custom URL fetcher that explicitly disallows
file://URLs or filters access based on allowed paths.
Mitigating System Information Leaks
WeasyPrint and its dependencies (Pango, etc.) may leak information about installed fonts, network configuration, or library versions. Use the isolation methods above to minimize the impact of such leaks.
Sponsor WeasyPrint development
mainYou can support the development of WeasyPrint, including bug fixes, new features, and documentation improvements, through donations and sponsorship via Open Collective.Build WeasyPrint documentation with Sphinx
mainDocumentation is managed with
Sphinxand is located in thedocsfolder. To build the documentation locally, run:venv/bin/sphinx-build docs docs/_buildOnce built, you can view the documentation by opening
docs/_build/index.htmlin your web browser.Optimize images and use caching
mainTo control image size and quality in the generated PDF, use the following parameters:
optimize_images: Enables size optimization (may increase rendering time).jpeg_quality: Sets JPEG quality from0(smallest size) to95(best quality).dpi: Sets the resolution in dots per inch to reduce raster image size.cache: Allows sharing an image cache between documents to save network and CPU time. You can pass a dictionary for in-memory caching or a string representing a folder path for disk-based caching (via--cache-folderCLI).
# Optimized lower-quality images, slightly slower but smaller PDF HTML('https://weasyprint.org/').write_pdf( 'weasyprint.pdf', optimize_images=True, jpeg_quality=60, dpi=150 ) # Using a shared cache between multiple documents cache = {} for i in range(10): HTML(f'https://weasyprint.org/').write_pdf( f'example-{i}.pdf', cache=cache )Attach files to a PDF
mainYou can attach files to a PDF using three different methods:
- HTML Anchor: Use
<a rel="attachment" href="filename.ext">for links that open the file. - HTML Link Tag: Use
<link rel="attachment" href="filename.ext">in the<head>to attach a file globally to the document. - CLI/Python: Use the
--attachmentCLI flag (can be used multiple times) or theweasyprint.Attachmentclass in Python.
<!-- Method 1: Anchor --> <a rel="attachment" href="note.txt">view attached note</a> <!-- Method 2: Global Link --> <link rel="attachment" href="note.txt">$ weasyprint document.html --attachment note.txt --attachment photo.jpg document.pdffrom weasyprint import Attachment, HTML attachments = [Attachment("note.txt"), Attachment("photo.jpg")] HTML(string="<p>PDF with attachments</p>").write_pdf("recipe.pdf", attachments=attachments)- HTML Anchor: Use
Install WeasyPrint on Alpine Linux
mainTo install WeasyPrint using the system package manager:
apk add weasyprintTo install inside a virtualenv using wheels, you need these dependencies:
apk add py3-pip so:libgobject-2.0.so.0 so:libpango-1.0.so.0 so:libharfbuzz.so.0 so:libharfbuzz-subset.so.0 so:libfontconfig.so.1 so:libpangoft2-1.0.so.0To install inside a virtualenv without using wheels (building from source), you need these dependencies:
apk add py3-pip so:libgobject-2.0.so.0 so:libpango-1.0.so.0 so:libharfbuzz.so.0 so:libharfbuzz-subset.so.0 so:libfontconfig.so.1 so:libpangoft2-1.0.so.0 apk add gcc musl-dev python3-dev zlib-dev jpeg-dev openjpeg-dev libwebp-dev g++ libffi-devapk add weasyprintRun WeasyPrint tests with pytest
mainTests are located in the
testsfolder and usepytest.Prerequisites:
- Ghostscript: Must be installed and available on your local PATH.
- DejaVu fonts: Recommended if you are on Linux.
Run the tests using:
venv/bin/python -m pytestGenerate specialized PDF variants (PDF/A, PDF/UA, PDF/X)
mainWeasyPrint can generate specialized PDF variants using the
--pdf-variantCLI option or thepdf_variantparameter in theHTML.write_pdfmethod. Supported variants can be listed viaweasyprint --help.Important Note: To ensure a valid document, your HTML and CSS must comply with the specific limitations of the chosen standard. Even if WeasyPrint attempts to generate a valid document, compliance is not guaranteed if the source content violates the specification.
from weasyprint import HTML HTML(string="<p>document</p>").write_pdf("document.pdf", pdf_variant="pdf/a-3u")