PDF generation library with fluent API and optional markdown support
Project description
PDFMarQ
PDF generation with a fluent API. Core is lean (reportlab + Pillow + svglib). Optional [md] extra adds full markdown-to-PDF rendering with banner headers, math, mermaid, syntax highlighting and more.
Philosophy
PDFMarQ wraps reportlab's stateful canvas into a fluent, cursor-based API. You describe document flow, not coordinates. Markdown rendering lives in a separate subpackage so the core stays installable without heavyweight dependencies.
- Fluent over imperative:
pdf.font("Helvetica", 12).text("Hi").enter().text("World")vscanvas.setFont() → canvas.drawString() → manual Y tracking - Cursor flows naturally: top-left origin,
ygrows down,enter()is a newline - One way per feature:
pdf.table(),pdf.image(),pdf.svg(),pdf.link(), no overloaded call signatures - Markdown is optional: core → 3 deps,
[md]adds the stack - Banner as contract: YAML frontmatter block becomes a styled banner with logo, status badge, version, dates, signature slot
- Lean output: no headless Chrome, no web stack, no React SSR. Pure Python + native PDF primitives. Files stay small, rendering stays fast, fonts are embedded properly, and the output opens clean in every PDF reader
Trade-offs:
- Cursor mutation is a state machine. Great for linear documents, awkward for complex grid layouts. For those, drop into raw reportlab via
pdf._canvas. - Markdown rendering estimates heights analytically to decide page breaks. Good enough for 95% of content. Edge cases with math + wide tables may push onto the next page more aggressively than necessary.
- Installing Python + a stack of deps is a barrier for non-technical users. If you're building a tool end-users will actually touch, put PDFMarQ behind a backend service (FastAPI endpoint, CLI wrapper, desktop app) rather than asking them to
pip installanything.
Install
pip install pdfmarq # core: reportlab, Pillow, svglib
pip install pdfmarq[md] # + markdown rendering stack
Examples
from pdfmarq import PDF
# Fluent core API
with PDF("report.pdf") as pdf:
pdf.font("Helvetica", 20, "Bold").text("Quarterly Report")
pdf.enter().font(size=12, mode="Regular")
pdf.text("Revenue up 23% year-over-year.")
pdf.table(
[["Q1", "120k"], ["Q2", "148k"], ["Q3", "172k"]],
header=["Quarter", "Revenue"],
sizes=[1, 2], aligns=["C", "R"],
)
pdf.image("chart.png", 180, 80)
pdf.link("https://xaeian.com", 40, 5)
from pdfmarq.md import md_to_pdf, MarkdownStyle
# Markdown to PDF
style = MarkdownStyle(
body_family="IBMPlexSans",
head_family="Sora",
page_number_label="Page", # "Page 1/5" in footer
)
md_to_pdf(open("doc.md").read(), "doc.pdf", style=style, font_dir="./fonts")
Markdown features
- GitHub-flavored markdown (tables, fenced code, lists, strikethrough)
- YAML frontmatter rendered as a styled banner (logo, status badge, version, sign block, landscape flag)
- Mini-banner on continuation pages with aspect-aware logo (width + height caps)
- Page numbering
Page N/Mvia deferred canvas rendering (configurable) - Configurable banner labels for localization (
banner_label_author,banner_label_created, …) - Skip-duplicate-title: drops
# Xwhen it matches frontmattertitle - Auto-slugged headings with clickable
[text](#anchor)internal links (unicode-aware, broken targets degrade to plain text) - Local-path links configurable via
link_root+link_base(or per-doc YAMLbase:) - Syntax highlighting (Pygments)
- Math formulas inline
$x^2$and block$$...$$(matplotlib) - Mermaid diagrams via
mermaid-cli(local) ormermaid.ink(network fallback), capped at a configurable max height - Footnotes, emoji shortcodes
:rocket:, nested lists, blockquotes, GitHub callouts (> [!NOTE],> [!WARNING], …) - Zebra-striped tables (subtle, readability without noise)
- Smart page breaks for paragraphs, tables, lists, and blockquotes (pre-measured, no orphans)
Modules
| Module | Description | Docs |
|---|---|---|
pdfmarq |
Core PDF API (fluent cursor-based drawing) | pdfmarq/readme.md |
pdfmarq.md |
Markdown-to-PDF renderer (optional [md] extra) |
pdfmarq/md/readme.md |
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 Distribution
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 pdfmarq-0.1.1.tar.gz.
File metadata
- Download URL: pdfmarq-0.1.1.tar.gz
- Upload date:
- Size: 67.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54181c2177d225004b75a04b2a2bcc1cae8aa3c7035380df839a183c3263f207
|
|
| MD5 |
a2448941078aed5f71ebb35f97d92c3b
|
|
| BLAKE2b-256 |
d32515f14830d59978dd66b3b0c1c386551770a18ffc3758aa006e6a56afb856
|
Provenance
The following attestation bundles were made for pdfmarq-0.1.1.tar.gz:
Publisher:
publish.yml on Xaeian/PDFMarQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pdfmarq-0.1.1.tar.gz -
Subject digest:
54181c2177d225004b75a04b2a2bcc1cae8aa3c7035380df839a183c3263f207 - Sigstore transparency entry: 1359388267
- Sigstore integration time:
-
Permalink:
Xaeian/PDFMarQ@56fb4f872fbe2e2a3107c3699abcbc11957bdb90 -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/Xaeian
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@56fb4f872fbe2e2a3107c3699abcbc11957bdb90 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pdfmarq-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pdfmarq-0.1.1-py3-none-any.whl
- Upload date:
- Size: 76.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1fedefddcce4cb2e054ee6a5f494393f4c9e21f901015470885291a343de058
|
|
| MD5 |
654a32ce0f3bfb932b54399fb2cef511
|
|
| BLAKE2b-256 |
6866f424b8fec2fb57213ca7d69ffcce73b695aaf4f3ad96c57b58c21dc187a7
|
Provenance
The following attestation bundles were made for pdfmarq-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on Xaeian/PDFMarQ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pdfmarq-0.1.1-py3-none-any.whl -
Subject digest:
c1fedefddcce4cb2e054ee6a5f494393f4c9e21f901015470885291a343de058 - Sigstore transparency entry: 1359388382
- Sigstore integration time:
-
Permalink:
Xaeian/PDFMarQ@56fb4f872fbe2e2a3107c3699abcbc11957bdb90 -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/Xaeian
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@56fb4f872fbe2e2a3107c3699abcbc11957bdb90 -
Trigger Event:
release
-
Statement type: