Professional Markdown to PDF converter for Persian, English, and mixed RTL/LTR technical documents
This repository contains Mardas MD2PDF, a Markdown-to-PDF publishing tool designed for clean Persian, English, and mixed-language documents.
The project converts single Markdown documents or ordered multi-file books into print-ready PDF files with support for RTL/LTR direction handling, Persian-friendly typography, cover pages, tables of contents, PDF outline bookmarks, deterministic figure/table/equation/listing numbering, semantic cross-references, generated reference lists, offline BibTeX/CSL JSON citations and bibliographies, GitHub-style Markdown features, MathJax formulas, enhanced syntax-highlighted code, offline Mermaid flowchart-subset diagrams, local images, footnotes, callouts, safe HTML, watermarks, and a clean appearance system built around styles, palettes, and light/dark modes.
The main goal of the project is to make technical Markdown documents publishable as polished PDF outputs without forcing the author to leave the Markdown workflow.
Markdown -> Structured HTML -> Chromium PDF
The system is organized around a browser-based rendering pipeline. Markdown is first parsed and normalized, then converted into a complete HTML document with appearance CSS, cover metadata, table of contents, MathJax configuration, and print rules. Finally, Playwright controls Chromium to generate the final PDF.
The Markdown layer also normalizes visual captions for images, tables, code listings, and Mermaid diagrams so the PDF layer can keep each caption with its associated print block. The reference engine assigns stable numbers and destinations to labeled objects, resolves semantic references before bidi isolation, and can generate lists of figures, tables, equations, and listings. The citation engine loads bounded local BibTeX or CSL JSON sources, resolves author-date or numeric citations after book assembly, and generates one linked bibliography without network metadata lookup.
The Markdown layer handles front matter, heading collection, table of contents and PDF outline generation, GitHub-style task lists, alerts, autolinks, heading anchors, image captions, enhanced code blocks with titles, line numbers, line highlights, and line-start metadata, Mermaid flowchart-subset diagrams, extended callouts, footnotes, safe HTML, local image embedding with blocked placeholders, print-fit wide tables, math protection, and direction-aware document metadata.
Print-flow rules now keep headings with their first block, protect ordinary paragraphs from orphan/widow lines, and let long code blocks or large tables split only when avoiding the split would waste page space.
PDF navigation is kept consistent across both navigation layers: the visible table of contents and the PDF viewer outline/bookmarks both jump to the same real heading destinations after metadata writing and cover/content merging.
The renderer builds the final printable HTML, validates page size and margin options, applies the selected style, palette, and mode, renders MathJax when enabled, separates the cover from numbered content pages, applies mode-aware watermark overlays, writes PDF metadata and bookmarks, adds stable page labels and running footers, and exports the result through Chromium.
The project provides two user-facing interfaces:
mrs-md2pdffor command-line and automation workflows.mrs-md2pdf-guifor local browser-based editing, previewing, option selection, PDF export, and browser-local workspace persistence.
The README is intentionally short. Mardas MD2PDF uses a guide-first documentation model:
- English Guide — the complete English user manual and live rendering sample.
- راهنمای فارسی — the complete Persian/RTL user manual and live rendering sample.
- Documentation map — the small index for release, maintenance, security, and documentation policy files.
Generated PDF versions of the guides are available in the examples/ directory. Feature documentation is not split across parallel reference pages; user-facing explanations, runnable examples, and renderer smoke cases belong in the guides so the Markdown source and the official PDFs stay synchronized.
Release and operations references are Changelog, Release checklist, Maintenance workflow, Security policy, and Documentation policy.
git clone https://github.com/mragetsars/Mardas-MD2PDF.git
cd Mardas-MD2PDF
python -m venv .venv
source .venv/bin/activate
pip install -e .
python -m playwright install chromiumRender a PDF:
mrs-md2pdf input.md -o output.pdf --toc --style modern --palette emerald --mode lightCreate a reusable project configuration and validate it without opening Chromium:
mrs-md2pdf init
mrs-md2pdf validate input.md
mrs-md2pdf explain-config input.md
mrs-md2pdf doctor input.mdThe nearest mardas.toml is discovered from the document directory upward. Command-line options override project values, which override equivalent front-matter values. Use --config, --no-config, and --format json for explicit automation workflows.
Create and build an ordered multi-file book:
mrs-md2pdf init my-book --book
mrs-md2pdf validate-book my-book
mrs-md2pdf explain-book my-book
mrs-md2pdf build-book my-bookBook Mode keeps chapter order in [book].chapters, namespaces heading and footnote IDs, embeds chapter-local or shared project-root assets, restores links between listed chapters, and produces one TOC, outline, cover, metadata set, and PDF artifact.
Enable semantic numbering and cross-references in a single document or book:
[references]
enabled = true
numbering_scope = "chapter"
list_of_figures = true
list_of_tables = trueSee @fig:architecture and @tbl:metrics.

*Figure. Processing architecture.* {#fig:architecture}
| Metric | Value |
| :--- | ---: |
| Accuracy | 0.98 |
Table: Evaluation metrics {#tbl:metrics}The supported semantic object prefixes are fig, tbl, eq, and lst. Labels are unique across the complete rendered document, including all chapters in Book Mode.
Enable an offline project bibliography:
[bibliography]
enabled = true
sources = ["references.bib"]
style = "author-date"
include_uncited = falsePrior work supports the result [@doe2024, p. 12].
Narrative form: @smith2023 describes the method.The built-in styles are author-date and numeric. Sources remain local to the project, Book Mode produces one bibliography for all chapters, and builds never perform DOI lookup or metadata downloads.
Cover branding is off by default so exported PDFs belong to the document owner. Enable explicit branding only when desired:
mrs-md2pdf input.md -o output.pdf --branding full --brand-name "Acme Research Lab"Explore appearance choices:
mrs-md2pdf --list-styles
mrs-md2pdf --list-palettes
mrs-md2pdf --list-modesLaunch the GUI for an independent document:
mrs-md2pdf-guiOpen a real mardas.toml project workspace:
mrs-md2pdf-gui --project path/to/projectProject Workspace mode adds a project file tree, Book Mode chapter badges, a Problems panel backed by the same structured diagnostics as the CLI, safe file opening/saving, renderer-backed preview for the active Markdown file, and full-book preview/export. Problem entries navigate to the responsible project file and line. Saves use content hashes and atomic replacement, so Studio rejects stale edits when a file changes externally.
Studio exports run through a bounded queue. The footer reports the real renderer stage, queue wait, and completion percentage; an active or queued export can be cancelled without terminating unrelated jobs. Chromium is reused by a dedicated worker only across trusted local exports, while every document receives a fresh browser context. Tune the local queue when needed:
mrs-md2pdf-gui --render-workers 2 --export-queue-size 6 --render-idle-timeout 60Measure the same deterministic performance profiles before and after renderer changes:
python scripts/benchmark_large_documents.py \
--profiles small,pages50,pages250,editor-loop \
--mode both \
--repeats 3 \
--output-dir build/performanceAudit source accessibility before rendering and inspect the final PDF without making unverified standards claims:
mrs-md2pdf audit-accessibility report.md
mrs-md2pdf audit-book-accessibility path/to/book
mrs-md2pdf audit-pdf dist/book.pdf --profile allSource audits check declared language, heading hierarchy, image alternative text, link names, table headers/captions, and the selected theme's text contrast. PDF audits inspect catalog language, XMP metadata, font embedding, ToUnicode maps, tagging signals, JavaScript, attachments, output intents, and PDF/A identifiers. JSON output and --fail-on error|warning|never make the commands suitable for CI. These are readiness checks: Mardas MD2PDF does not claim PDF/UA or PDF/A conformance without an independent standards validator.
Tagged release workflows verify the project on Linux, Windows, and macOS, build deterministic wheel/source artifacts, generate an SPDX 2.3 runtime SBOM, and create platform-specific offline Python wheel bundles. The bundles contain the project wheel and resolved runtime dependency wheels, but deliberately do not claim to include Chromium or a standalone Python runtime.
Verify a downloaded release directory before installing:
sha256sum -c CHECKSUMS.sha256
python scripts/finalize_release_artifacts.py \
--artifact-dir . \
--version X.Y.Z \
--require-sbom \
--verify-onlyOfficial GitHub artifacts can also be verified against their signed provenance:
gh attestation verify mardas_md2pdf-X.Y.Z-py3-none-any.whl \
--repo mragetsars/Mardas-MD2PDFAn offline Python bundle is installed from its extracted directory:
python install.py --target mardas-md2pdf-venvThe installer verifies the embedded checksums and invokes pip with --no-index. PDF rendering still requires a compatible Chromium executable; the optional python -m playwright install chromium step may require network access.
The Studio interface groups export settings into Document, Appearance, Branding, Layout, and Advanced sections. Appearance and branding choices use visual cards, while advanced controls such as watermarks and local assets stay collapsed until needed. The Open Bundle and Save Bundle controls handle portable .mardas.json snapshots containing Markdown, export options, and attached assets; they are separate from the live on-disk Project Workspace opened with --project. Studio also supports drag-and-drop asset management, auto-scaling PDF-like renderer-backed preview, Fast approximate browser-local preview, debug HTML export, and a command palette via Ctrl/Cmd+K. In Project Workspace mode, Ctrl/Cmd+S saves the active project file; Ctrl/Cmd+Shift+S saves a portable bundle, and Ctrl/Cmd+Enter exports the normal single-document PDF. The complete Studio walkthrough lives in the guides.
The project is organized as follows:
Mardas-MD2PDF/
├── src/mardas_md2pdf/ # Python package source
│ ├── markdown.py # Markdown parsing, front matter, TOC, math, Mermaid, footnotes, safe HTML
│ ├── mermaid.py # Offline Mermaid flowchart-subset-to-SVG renderer
│ ├── renderer.py # HTML assembly, appearance CSS, MathJax, Chromium PDF rendering
│ ├── references.py # Numbered objects, semantic labels, cross-references, and generated lists
│ ├── citations.py # Offline BibTeX/CSL JSON parsing, citation resolution, and bibliography output
│ ├── book.py # Ordered chapter manifest, namespacing, cross-links, and book assembly
│ ├── cli.py # Conversion command-line interface
│ ├── config.py # Versioned mardas.toml discovery, validation, and resolution
│ ├── diagnostics.py # Stable text/JSON diagnostic records
│ ├── project_commands.py # Project diagnostics plus init/build/validate/explain Book Mode workflows
│ ├── workspace.py # Safe Studio project tree, file I/O, diagnostics, preview, and Book export
│ ├── render_pool.py # Bounded export workers with thread-affine reusable Chromium sessions
│ ├── studio_jobs.py # Disk-backed Studio export jobs, progress, cancellation, and retention
│ ├── gui.py # Local browser-based GUI backend
│ └── assets/ # Style CSS, GUI shell, logo, and vendored MathJax files
├── docs/ # Guides, changelog, release, maintenance, security, and documentation policy
│ └── guides/ # Complete English and Persian user guides
├── examples/ # Generated PDF examples from the guide files
├── scripts/ # Helper scripts for checks, examples, distributions, visual QA, and cleanup
├── tests/ # Automated pytest test suite
├── pyproject.toml # Package metadata and dependencies
├── .github/workflows/ # CI and release artifact automation
├── LICENSE # MIT license
└── README.md # Project introduction
The examples/ directory contains generated PDF outputs of the guide files:
examples/
├── GUIDE.en.pdf
└── GUIDE.fa.pdf
These files are intended to show the real PDF output produced by the current documentation. They are also used as release-facing print samples during typography and media audits.
Mardas MD2PDF is intended for local publishing workflows. Local Markdown images and all front-matter branding logos are resolved relative to the Markdown document, restricted to regular supported image files inside that document root, and embedded before Chromium renders the PDF. Out-of-bound paths, symlink escapes, unsupported files, and oversized images are rejected or rendered as visible blocked placeholders. Relative filesystem links remain readable text but are not exported as machine-local file: annotations.
Bibliography sources are bounded local .bib or CSL .json files resolved inside the document/project root; citation rendering performs no network lookup and accepts only validated internal citation keys.
Remote http(s) images are blocked by default for privacy; use --allow-remote-assets only for trusted documents that intentionally fetch network images. Studio Fast Preview follows the same privacy boundary: it does not fetch remote or local image paths, and it disables unsafe or filesystem link schemes. Raw HTML is sanitized unless --unsafe-html is used, and safe data: image URLs are limited to common raster formats.
Chromium sandboxing is configurable with --chromium-sandbox auto|on|off; the default auto keeps sandboxing enabled for normal users and disables it only when running as root in container-style environments. Output PDF and debug HTML files are committed atomically, and the CLI rejects input/output/debug paths that resolve to the same file. Reference labels are document-internal identifiers only: they do not expand filesystem access, enable scripts, or bypass the existing asset and HTML trust boundaries. See docs/SECURITY.md for the full trust boundary.
pip install -e .[dev]
./scripts/check.sh
python -m pytest -q tests/test_cross_references.py tests/test_book_mode.py
python scripts/benchmark_large_documents.py --profiles small,editor-loop --mode both --repeats 2Clean local build and patch artifacts when the working tree starts to feel noisy:
./scripts/clean_workspace.sh
./scripts/clean_workspace.sh --patches # also remove a temporary root-level patches/ directoryThe official guide PDFs also exercise document-local image embedding with semantic figure captions and safe HTML image sizing.
The release workflow runs the consolidated release gate before publishing artifacts. It rebuilds and preflights the English and Persian guide PDFs, performs visual QA, installs the wheel in a clean environment, verifies packaged assets and entry points, and emits checksums for deterministic wheel and source-distribution artifacts.
The test suite covers Markdown transformation, GitHub-style features, direction handling, table of contents and outline generation, enhanced code highlighting, code-fence metadata, Mermaid SVG rendering, MathJax preservation, extended callouts, safe HTML, footnotes, local and remote image boundaries, renderer options, GUI availability, Studio option validation, page-size handling, wide-table print fitting, workspace persistence, deterministic example metadata, appearance validation, and fallback warnings. For visual changes to styles, palettes, or light/dark mode, run python scripts/audit_appearance_matrix.py --output-dir build/appearance-audit --render-png --resume and inspect the generated matrix. For complete chunked coverage across every style, palette, and mode plus the feature-heavy sample, run python scripts/run_visual_qa_matrix.py --output-dir build/visual-qa/full --render-png --resume; the summary file records active-chunk heartbeat data and skipped completed chunks. For targeted feature-heavy coverage, run python scripts/audit_pdf_features.py --all-appearances --render-png --resume.
This project was developed and maintained by:
This project is licensed under the MIT License. See LICENSE for details.
