Skip to main content

PDFMarQ

PDF generation with a fluent API. Core is lean (reportlab + Pillow + svglib). Optional [md] extra adds full markdown-to-PDF rendering: documentation with banner headers, letters and contracts in one or two columns, 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") vs canvas.setFont() → canvas.drawString() → manual Y tracking
  • Cursor flows naturally: top-left origin, y grows 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
  • Engine and documents apart: pdfmarq.md draws markdown content, a document package lays out the page around it
  • Banner as contract: in pdfmarq.paper YAML frontmatter becomes a styled banner with logo, status badge, version, dates
  • Letters and contracts: pdfmarq.legal sets a letter header from frontmatter and signing lines from the style, in one or two columns, or with language versions side by side
  • Templates and series: pdfmarq.merge fills a markdown template with one record, or with each record of a table, a document per record
  • 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 the raw reportlab canvas via pdf.c.
  • 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 install anything.

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.paper import md_to_pdf, PaperStyle
# Markdown documentation to PDF
style = PaperStyle(
  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")
from pdfmarq.legal import md_to_pdf, md_parallel_to_pdf, lang_style
# A contract in two balanced columns, signed by both parties
md_to_pdf(open("contract.md").read(), "contract.pdf",
  style=lang_style("pl", columns=2, sign="contract"), font_dir="./fonts")
# Language versions side by side, each from its own file
md_parallel_to_pdf([pl_text, en_text], "contract-pl-en.pdf",
  styles=[lang_style("pl"), lang_style("en")], 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, dates) by pdfmarq.paper
  • Letters, statements and contracts by pdfmarq.legal: letter header from frontmatter, justified text that flows, two balanced columns, language versions side by side (see legal/guide)
  • Mail merge by pdfmarq.merge: placeholders, conditions, loops and included clauses, every record checked before the first document (see merge/readme)
  • Columns in the core API: pdf.columns(2), and everything markdown draws flows through them
  • Page geometry, fonts, banner toggles and locale come from caller's style=, never from the document (see md/guide)
  • Mini-banner on continuation pages with aspect-aware logo (width + height caps)
  • Page numbering Page N/M via 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 # X when it matches frontmatter title
  • 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
  • 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) or mermaid.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

  • pdfmarq: core PDF API (fluent cursor-based drawing, columns)
  • pdfmarq.md: markdown engine (optional [md] extra)
  • pdfmarq.paper: documentation with a frontmatter banner
  • pdfmarq.legal: letters, statements, contracts, parallel versions
  • pdfmarq.merge: mail merge, one record or a document per record of a table

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, letters and contracts) works the same in both.

Metadata

Release files for pdfmarq 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pdfmarq 0.6.1
File Size Uploaded Provenance Actions
pdfmarq-0.6.1.tar.gz 221.8 kB With provenance Details for pdfmarq-0.6.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pdfmarq 0.6.1
File Interpreter ABI Platform Actions
pdfmarq-0.6.1-py3-none-any.whl Python 3 none any Details for pdfmarq-0.6.1-py3-none-any.whl

Total release size: 408.0 kB

Release files / pdfmarq-0.6.1.tar.gz

Download URL pdfmarq-0.6.1.tar.gz
Size 221.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d80dc61a483fab885590b68db950841ebd67c94c6c96b735dad0d2e2610ca876
BLAKE2b-256 checksum
How to use checksums
fd08d1bc66211a7d97fcab415dc01025449d2b084b5d378e1722a01c89cee123
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 Oct 14, 2026.

Transparency log

Release files / pdfmarq-0.6.1-py3-none-any.whl

Download URL pdfmarq-0.6.1-py3-none-any.whl
Size 186.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0858111ba25014e4c20e3cfee51da55c5ef0af693a787de1c7ea8416f39de906
BLAKE2b-256 checksum
How to use checksums
6280fbbddcc0911a7e5a9986b84b0d8eac07ae26cc14e6203b3d46274a80b308
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 Oct 14, 2026.

Transparency log

Security for pdfmarq 0.6.1

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.

Select from 2 files

Attestation for pdfmarq-0.6.1.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 Oct 14, 2026.

Transparency log

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page