A fast, minimal PDF page renderer
Project description
rupdf
A fast, minimal PDF renderer in Rust with Python bindings. Takes pre-laid-out pages and renders them to PDF bytes.
Features
- Text with TTF/OTF fonts, horizontal/vertical alignment, and colors
- Rectangles with stroke, fill, and rounded corners
- Lines with configurable width
- Images (PNG, JPEG, WebP, SVG)
- Barcodes (Code 128) and QR codes
- Font subsetting - embeds only used glyphs
- Compression - optional zlib compression
Installation
pip install rupdf
Usage
import rupdf
doc = {
"metadata": {
"title": "My Document",
"author": "Jane Doe"
},
"pages": [
{
"size": (612, 792), # Letter size in points
"background": (255, 255, 255, 255),
"elements": [
{
"type": "text",
"x": 72,
"y": 72,
"text": "Hello, World!",
"font": "main",
"size": 24,
"color": (0, 0, 0, 255)
},
{
"type": "rect",
"x": 72,
"y": 120,
"w": 200,
"h": 100,
"stroke": 1.0,
"stroke_color": (0, 0, 0, 255),
"fill_color": (240, 240, 240, 255)
}
]
}
],
"resources": {
"fonts": {
"main": {"path": "/path/to/font.ttf"}
# Or: "main": {"bytes": font_bytes}
},
"images": {
"logo": {"path": "/path/to/logo.png"}
# Or: "logo": {"bytes": image_bytes}
}
}
}
# Render to PDF bytes
pdf_bytes = rupdf.render_pdf(doc, compress=True)
# Write to file
with open("output.pdf", "wb") as f:
f.write(pdf_bytes)
Coordinate System
- Origin: top-left corner of the page
- Units: points (1 point = 1/72 inch)
- Y-axis: increases downward
Common page sizes:
- Letter: 612 x 792 points
- A4: 595 x 842 points
Element Types
Text
{
"type": "text",
"x": 72,
"y": 72,
"text": "Hello",
"font": "font_ref", # Reference to fonts in resources
"size": 12, # Font size in points
"color": (0, 0, 0, 255), # RGBA (optional, default black)
"align": "left", # "left", "center", or "right" (optional)
"vertical_anchor": "baseline" # "baseline", "capline", or "center" (optional)
}
Positioning:
(x, y)specifies the anchor point of the textaligncontrols horizontal alignment relative to x:"left"(default): text extends to the right of x"center": text is centered on x"right": text extends to the left of x
vertical_anchorcontrols vertical alignment relative to y:"baseline"(default): y is the text baseline"capline": y is the top of capital letters"center": y is the vertical center of capital letters
TextBox
Multi-line text with word wrapping, like Illustrator's "area type".
{
"type": "textbox",
"x": 72,
"y": 72,
"w": 200,
"h": 100,
"text": "Long text that will wrap within the box...",
"font": "font_ref",
"size": 12,
"line_height": 14.4, # Optional, default = size * 1.2
"color": (0, 0, 0, 255), # Optional, default black
# Box alignment (how the box is positioned relative to x, y)
"box_align_x": "left", # "left", "center", or "right" (optional)
"box_align_y": "top", # "top", "center", or "bottom" (optional)
# Text alignment (how text is positioned inside the box)
"text_align_x": "left", # "left", "center", or "right" (optional)
"text_align_y": "baseline" # "top", "capline", "center", "baseline", or "bottom" (optional)
}
Two-Layer Alignment:
-
Box alignment - positions the box relative to
(x, y):box_align_x: left=x is left edge, center=x is center, right=x is right edgebox_align_y: top=y is top edge, center=y is center, bottom=y is bottom edge
-
Text alignment - positions text inside the box:
text_align_x: per-line horizontal alignment (left/center/right)text_align_y: vertical alignment of the text block:"top": ascender of first line at box top"capline": cap height of first line at box top"center": text block vertically centered"baseline"(default): last line's baseline at box bottom"bottom": descender of last line at box bottom
Notes:
- Text wraps at word boundaries to fit within
w - Overflow is clipped to box bounds
- Explicit
\nin text creates line breaks
Rectangle
{
"type": "rect",
"x": 72,
"y": 72,
"w": 100,
"h": 50,
"stroke": 1.0, # Stroke width (0 for no stroke)
"stroke_color": (0, 0, 0, 255), # Optional
"fill_color": (255, 255, 255, 255), # Optional
"corner_radius": 10 # Optional, for rounded corners
}
Notes:
(x, y)is the top-left cornercorner_radiuscreates rounded corners; automatically clamped to half the smallest dimension
Line
{
"type": "line",
"x1": 72,
"y1": 72,
"x2": 200,
"y2": 72,
"stroke": 1.0,
"color": (0, 0, 0, 255)
}
Image
{
"type": "image",
"x": 72,
"y": 72,
"w": 200,
"h": 150,
"image_ref": "logo" # Reference to images in resources
}
Supported formats: PNG, JPEG, WebP (rasterized to 300 DPI), SVG (rendered as vectors).
Barcode (Code 128)
{
"type": "barcode",
"x": 72,
"y": 72,
"w": 200,
"h": 60,
"value": "ABC-123",
"human_readable": True, # Show text below barcode
"font": "font_ref", # Required if human_readable
"font_size": 10
}
QR Code
{
"type": "qrcode",
"x": 72,
"y": 72,
"size": 100, # QR codes are square
"value": "https://example.com",
"color": (0, 0, 0, 255), # Foreground (dark modules)
"background": (255, 255, 255, 255) # Background (light modules)
}
Error Handling
try:
pdf = rupdf.render_pdf(doc)
except rupdf.RupdfError as e:
print(f"Failed to render: {e}")
Common errors:
- Missing font or image reference
- Invalid page dimensions
- Missing required element fields
- Character not found in font
Performance
Benchmarks comparing rupdf to ReportLab (10 iterations each):
| Benchmark | rupdf | ReportLab | Speedup |
|---|---|---|---|
| Empty page | 0.02ms | 0.27ms | 13x |
| 50 text lines | 0.82ms | 0.82ms | 1x |
| 100 rectangles | 0.19ms | 1.02ms | 5x |
| 10 pages | 1.62ms | 3.80ms | 2x |
Development
# Build
maturin develop
# Run tests
cargo test # Rust unit tests
pytest python/tests/ -v # Python tests
# Generate test PDF with all element types
python scripts/generate_test_pdf.py # Without images
python scripts/generate_test_pdf.py --svg logo.svg --png photo.png # With images
# Benchmarks
python benchmarks/run_benchmark.py
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rupdf-0.1.7.tar.gz.
File metadata
- Download URL: rupdf-0.1.7.tar.gz
- Upload date:
- Size: 2.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77f8f44b6a24a1e6eaebb554cbdebd726dde5b5129c02c4c36bcefb217ff3809
|
|
| MD5 |
2a25cf64f5b95e8a59e104d261a4c485
|
|
| BLAKE2b-256 |
2d1af2affbc3dd5108835f23ff5e58874552863f4333a4d01e860627e4abf955
|
File details
Details for the file rupdf-0.1.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rupdf-0.1.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c41a77ee5f37a011ce4547f21d353dcce022ba3469ba8c07ccaa0a2589b4fcd1
|
|
| MD5 |
6c622af463da63219f518bfb65cb585c
|
|
| BLAKE2b-256 |
b38b00c92a466481b47af0874d9467053b22d4bf4c432da3b1dead55277233ea
|
File details
Details for the file rupdf-0.1.7-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: rupdf-0.1.7-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.1 MB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff51c8af76138bf884c1a79b3ca72afe62e570694ece65b1713b4dd4fa50fe2f
|
|
| MD5 |
f73f5eb1c1ff10bfdb48396ca77309a6
|
|
| BLAKE2b-256 |
fdb31264ebb9e3040ed507d5d9778ee2c4a2820ba58ab242c78e4e646ad8e783
|
File details
Details for the file rupdf-0.1.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rupdf-0.1.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e321caaf3aa5061f4737365a631d8966988de59049b47a37ab03a9508408ce4
|
|
| MD5 |
380c0e33a9f3384590d36bcab9d17be5
|
|
| BLAKE2b-256 |
dbb6b1da9e51306ffd660f3f59e9d23c120aec1966ac9143a9b084967f005249
|
File details
Details for the file rupdf-0.1.7-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: rupdf-0.1.7-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.1 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e69ad6331f4d11c909bfa8642954418c71fbbf1e7bc15f0e97d3ba58ebc6a39b
|
|
| MD5 |
90609e4b29522cd57a7abd21ce27cc6d
|
|
| BLAKE2b-256 |
3c3f5eb688d21a2852fbff23306fa53352f4faf6ad065b8c70c3c4cf7a27d8c5
|
File details
Details for the file rupdf-0.1.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rupdf-0.1.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8709ab3dca8459437e7acf7e056bc3535aa3796643cf20c7446e80718521c19e
|
|
| MD5 |
0b5ec3c2512172731f26902971b6f84e
|
|
| BLAKE2b-256 |
e1ae3cb0804c5a724c0188fa4df7563b87a139785dcbe56b900b6649b25299b3
|
File details
Details for the file rupdf-0.1.7-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: rupdf-0.1.7-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.1 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2694e966c714e038607b6ba404e4347fd19a9ec6c62800a87e290729ddbd1141
|
|
| MD5 |
858e8ca7b14953e5d3a1c677aa68283a
|
|
| BLAKE2b-256 |
2771f96e6d613bff81ddf17f25f5965a764209733d7dfae4970801e493bfb0bf
|