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 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 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(
font_body="IBMPlexSans",
font_head="Sora",
page_number_label="Page", # "Page 1/5" in footer
)
md_to_pdf(open("doc.md").read(), "doc.pdf", style=style, font_dir="./fonts")
See example.py for an end-to-end CLI script.
It covers a language preset, custom TTF fonts from ./fonts/, link_root for cross-document references,
base_dir for relative images, and optional Ghostscript post-compression.
Markdown features
- GitHub-flavored markdown (tables, fenced code, lists, strikethrough)
- YAML frontmatter rendered as a styled banner (logo, status badge, version, sign block)
- Page geometry, fonts, banner toggles and locale come from caller's
style=, never from the document (seemd-guide) - Mini-banner on continuation pages with aspect-aware logo (width + height caps)
- Page numbering
Page N/Mvia deferred canvas rendering (configurable) - Built-in language presets (en|pl|de|fr|es|it|cs|sk) via
lang_style(): covers banner, callouts, date format, page numbers - 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$$...$$, drawn as vectors (MathJax, matplotlib fallback) - Images sized from their own resolution, capped by
image_max_h, centred - Images alone in a paragraph become a row of figures, wrapping into a grid beyond text width
- 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)
- Basic inline HTML pass-through (
<b>,<i>,<code>,<br>,<hr>)
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 |
See also
Need .docx instead of PDF?
Check DocMarQ, sibling library with the same API shape and .docx output.
Syntax highlighting is PDF-only, and math there covers a wider slice of LaTeX (DocMarQ emits native Word equations for the common subset).
Everything else (banner, callouts, mermaid, lang presets) works the same in both.
Metadata
Release files for pdfmarq 0.5.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pdfmarq-0.5.4.tar.gz | 156.1 kB | With provenance | Details for pdfmarq-0.5.4.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pdfmarq-0.5.4-py3-none-any.whl | Python 3 | none | any | Details for pdfmarq-0.5.4-py3-none-any.whl |
Total release size: 299.1 kB
Release files / pdfmarq-0.5.4.tar.gz
| Download URL | pdfmarq-0.5.4.tar.gz |
|---|---|
| Size | 156.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a5a933cff5e021aee737e489c92d3ed50df0623bebcd54f7e28022ae73847515
|
|
BLAKE2b-256 checksum How to use checksums |
ed98bdee982b4c93573df860539cb82418403395e213aa905926cc45b8c9ba39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / pdfmarq-0.5.4-py3-none-any.whl
| Download URL | pdfmarq-0.5.4-py3-none-any.whl |
|---|---|
| Size | 143.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a245de214484411de2a96dc7dd69fba715948e5bb0b5ea260e83a00b5e60cc43
|
|
BLAKE2b-256 checksum How to use checksums |
7e3872009875c606467b078e109d418ff8f396f12ee6b59a4a350f6f6ecffb5d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logSecurity for pdfmarq 0.5.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pdfmarq-0.5.4.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.