Skip to main content

The reverse of MarkItDown: turn Markdown into clean, themeable DOCX and PDF documents.

Project description

MarkItUp

The reverse of Microsoft's MarkItDown: feed it Markdown, get back clean, well-designed .docx and .pdf (and .html).

Unlike an LLM that "codes and executes" a document on every request, MarkItUp is a deterministic pipeline. The same Markdown + same theme always produces the same document. All design decisions are front-loaded into a theme, once — they are never re-derived per document.

markdown ──parse──▶ IR ──render──┬──▶ .docx   (python-docx → OOXML)
                                 ├──▶ .html   (theme → CSS)
                                 └──▶ .pdf    (IR → themed HTML → print engine)

PDF uses a pluggable engine: weasyprint (pure-Python, default) or chromium (headless, highest fidelity). Both consume the same HTML.

Install

pip install markitup-py            # docx only (lightweight)
pip install "markitup-py[pdf]"     # + PDF and existing-file watermarking

The import name is markitup. PDF needs system libs for WeasyPrint (pango, cairo, gdk-pixbuf).

Quick start (Python)

from markitup import MarkItUp

m = MarkItUp(theme="report")
m.convert("doc.md", "doc.pdf")
m.convert("doc.md")                 # -> ./doc.docx (current directory)

Configure once, convert many. Every knob overrides the theme:

from markitup import MarkItUp, Watermark

m = MarkItUp(
    theme="report",
    body_font="Georgia",
    heading_font="Calibri",
    text_color="#222222",
    heading_color="#0B3D2E",
    heading_colors={1: "#0B3D2E", 2: "#1F6FEB"},   # per-level overrides
    accent_color="#1F6FEB",
    base_size=11, scale=1.2, line_height=1.45,
    page_size="A4", margin_cm=2.54,
    banner="CONFIDENTIAL — INTERNAL USE ONLY",
    watermark=Watermark(enabled=True, text="DRAFT", opacity=0.08, position="center"),
)
m.convert("doc.md", "doc.pdf")

Fonts

DOCX stores font names and the reader substitutes what they have installed, so prefer cross-platform families. PDF is rendered here, so a font must be installed on this machine to appear.

from markitup import list_fonts, is_available
info = list_fonts()
info["installed"]   # families available for PDF rendering on this machine
info["safe"]        # curated cross-platform families for .docx
is_available("Georgia")
markitup fonts

Watermarks

A watermark is a theme token, applied identically to docx and PDF — text or image, with opacity, rotation, position (center/top/bottom).

m = MarkItUp(watermark={"text": "DRAFT", "opacity": 0.1, "rotation": -45})
m = MarkItUp(watermark={"image": "logo.png", "opacity": 0.12})

Stamp an EXISTING file

Add a watermark to a .pdf or .docx you already have — no re-rendering. It's an overlay/append, so the document's content is left intact.

from markitup import stamp

stamp("report.pdf", "stamped.pdf", "CONFIDENTIAL",
      position="top", opacity=0.12, pages="1-3", behind=True)
stamp("report.docx", "stamped.docx", {"image": "logo.png", "opacity": 0.1})
# encrypted PDF: pass password=...
markitup stamp report.pdf -o stamped.pdf --watermark CONFIDENTIAL --position top
markitup stamp report.docx -o stamped.docx --watermark-image logo.png

Encrypted PDFs are refused unless you supply a password. Scanned/image PDFs are fine — the overlay lands on top.

Banners

A short notice rendered in-flow at the very top of a generated document:

from markitup import Banner
m = MarkItUp(banner=Banner(text="RESTRICTED", color="#FFFFFF", bg="#B00020"))

Templates (base_docx)

Hand MarkItUp a Word file you designed — brand fonts, colors, a header/footer with your logo. It opens the file, clears the body, and maps your Markdown onto its named styles. The template owns the design; Markdown just fills it. (This is the Pandoc reference.docx model.)

m = MarkItUp(base_docx="brand-template.docx")
m.convert("doc.md", "out.docx")

CLI

markitup convert in.md -o out.pdf --theme report --font Georgia
markitup convert in.md --banner "CONFIDENTIAL" --watermark DRAFT
markitup fonts
markitup stamp in.pdf -o out.pdf --watermark "DO NOT COPY" --position bottom --pages 1-2

Supported Markdown

Headings, paragraphs, bold/italic/strike/code, links, ordered & unordered lists (nested), blockquotes, fenced code blocks, GFM tables (with column alignment and clean wrapping), and thematic breaks.

Architecture

Module Responsibility
markitup/ir.py Intermediate Representation — structure & intent only
markitup/theme.py Design tokens; computed type scale; watermark/banner
markitup/parse.py markdown-it-py token stream → IR
markitup/render_docx.py IR + Theme → .docx
markitup/render_html.py IR + Theme → HTML/CSS (PDF intermediate)
markitup/render_pdf.py HTML → PDF (pluggable engine)
markitup/stamp.py Watermark existing .pdf/.docx
markitup/fonts.py Font discovery
markitup/api.py The MarkItUp class
markitup/themes/*.yaml Named themes

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

markitup_py-0.3.1.tar.gz (27.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

markitup_py-0.3.1-py3-none-any.whl (29.7 kB view details)

Uploaded Python 3

File details

Details for the file markitup_py-0.3.1.tar.gz.

File metadata

  • Download URL: markitup_py-0.3.1.tar.gz
  • Upload date:
  • Size: 27.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for markitup_py-0.3.1.tar.gz
Algorithm Hash digest
SHA256 4801efc26899c7ffedf9f752e781e1e3cc0f568213a6909d8c3c80cb8f1975a5
MD5 74b7efb087307d940bdba2b8590c4ef2
BLAKE2b-256 08e593cf7461938f0831f037c89a252d1b6f9fa7c9a5db699cf15d007e27ed1c

See more details on using hashes here.

File details

Details for the file markitup_py-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: markitup_py-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 29.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for markitup_py-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0babd40a8e44742ea8c28abac6fe676d4c48adae61e3faaacf340d5d7c8de6cc
MD5 ea1d8caffb265b99417c8424a99db22a
BLAKE2b-256 25dcd76965a1ab3aeda951af042daa32a60eb601a35876d59e6e876b33d7e4de

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page