Markdown → profesionálně vysázené PDF. Vlastní řádkový Markdown parser + dva renderery: mPDF (default, čistě PHP) nebo headless Chrome + GhostScript (vektorový mermaid). Titulní strana, obsah, hlavička/patička, callouty, tabulky, auto-fit ASCII diagramů a render
mermaiddiagramů. Vše projektově specifické (cesty, výběr souborů, identita, překlad, logo) žije v jednommd2pdf.config.php— engine se nemění.
🇨🇿 Čeština (níže) · 🇬🇧 English
Ukázka generovaného PDF s Mermaid diagramem
md2pdf.php je samostatný PHP nástroj, který převede jeden nebo více Markdown souborů na profesionálně vysázená PDF. Umí dva režimy: výchozí jeden PDF na dokument, nebo combine — sloučení mnoha .md do jednoho PDF s jednou titulkou a průběžným obsahem (např. vícekapitolový manuál). Je navržený jako sdílený engine: nainstaluješ ho jednou (např. do c:\work\MD2PDF) a používáš napříč projekty — každý projekt má jen svůj md2pdf.config.php.
- Dva renderery —
mpdf(default, čistě PHP, bez závislostí) nebochrome(vektorový mermaid přes headless Chrome + GhostScript); přepíná se v configu, výstup je vizuálně sjednocený. - Vlastní Markdown parser (nadpisy, seznamy vč. vnořených a checkboxů, GFM tabulky se zarovnáním a zalomením buněk, blockquote/callouty, kód, obrázky, HR, poznámky pod čarou
[^1], odkazy vč. interních kotev a autolinků<url>, inline**bold**/*italic*/~~strike~~/code, escapování\*a tvrdé zalomení řádku dvěma mezerami nebo\na konci řádku). - Titulní strana s brandingem — titul z
# H1, podtitul/účel a metadata (verze, datum, autor) z úvodního blockquote, logo dole; full-bleed pozadí bez hlavičky/patičky. - Obsah (TOC) automaticky z
##nadpisů (když jsou aspoň 4). - Hlavička a patička + čísla stran v těle (titulka nečíslovaná); texty plně z configu (lokalizace).
- Callout boxy z blockquote; „varovné" (oranžové) podle klíčových slov.
- Dvě barevná témata —
violet(výrazné, prezentační) neboserious(grafitová, střízlivá — pro úřední/firemní dokumenty); přepíná se v configu, jednotlivé barvy jdou doladit. - Mermaid diagramy — renderer
chromevkládá ostré vektorové SVG, renderermpdfPNG přes mermaid-cli. - Auto-fit širokých code-bloků (ASCII diagramy) a tabulek; dlouhé tokeny (DNS/base64) se zalomí.
- Embedované volné fonty (Source Sans 3 + Cascadia Mono + DejaVu záloha) → PDF vypadá všude stejně a je legálně přenositelné.
- Stránkové zlomy — každá
# H1i## H2kapitola začíná na nové straně (H2 zlom lze vypnout zvlášť přesh2_page_break). - Combine režim — sloučení mnoha
.mddo jednoho PDF (vícekapitolový manuál): jedna titulka, jeden průběžný obsah (kapitoly H1 + sekce H2), pořadí zINDEX.md, cross-chapter.mdodkazy jako klikací interní kotvy.
| Nástroj | Verze | K čemu |
|---|---|---|
| PHP | 8.0+ (CLI, s mbstring) |
běh enginu (oba renderery) |
| Composer | — | instalace mPDF |
| Node.js + npm | 18+ | renderer chrome (puppeteer) a/nebo mermaid — volitelné |
| Chrome / Edge | jakýkoli Chromium | renderer chrome a render mermaidu — volitelné |
| GhostScript | — | renderer chrome (spojení + optimalizace); jinak volitelně náhledy |
Default renderer mpdf běží jen s PHP + Composer. Node/Chrome/GhostScript jsou potřeba jen pro renderer chrome; bez nich se použije mpdf a mermaid bloky se vysází jako PNG (mermaid-cli), případně jako kód.
Engine umí dva renderery (přepínač renderer v configu):
mpdf(default) — čistě PHP přes mPDF, bez Node/Chrome. Menší soubory. Mermaid jako PNG (mermaid-cli, volitelně).chrome— sazba přes headless Chrome + GhostScript: vektorový mermaid (SVG), downsample obrázků. Vyžaduje Node (puppeteer), Chrome/Edge a GhostScript; když Chrome chybí, spadne automaticky zpět nampdf.
Titulní strana je u obou stejná (full-bleed pozadí, bez hlavičky/patičky/čísla; běžící hlavička/patička + čísla stran jen v těle). Nastavení chrome rendereru (chrome.image_dpi, chrome.margins, cesty k exe/gs) viz md2pdf.config.sample.php.
Engine má dvě vestavěné palety (přepínač theme v configu, případně --theme= na CLI). Rozvržení a typografie jsou u obou identické — mění se jen barvy:
| Téma | Vzhled | Kdy |
|---|---|---|
violet (default) |
fialový branding, výrazný akcent | prezentace, produktová a interní dokumentace |
serious |
grafitově-černá se střízlivým vínovým akcentem: černá hlavička tabulky, šedé podklady, barva jen jako akcent | úřední/firemní dokumenty — upomínky, vyúčtování, smlouvy, reporty |
'theme' => 'serious',Jednotlivé barvy lze doladit klíčem theme_colors (přebíjí paletu token po tokenu; seznam tokenů viz THEME_PALETTES v md2pdf.php):
'theme_colors' => ['accent' => '#8f1d1d', 'cover_bg' => '#0f172a'],Když se má tentýž zdroj vysázet v obou variantách vedle sebe, přidej k výstupu příponu (output_suffix v configu nebo --suffix=):
php md2pdf.php # README.pdf (violet)
php md2pdf.php --theme=serious --suffix=-serious # README-serious.pdf (serious)git clone <repo> md2pdf
cd md2pdf
composer install # mPDF do vendor/
npm install # mermaid-cli (volitelné, jen pro mermaid)Pro mermaid je potřeba Chromium. Engine automaticky najde systémový Chrome/Edge. Pokud žádný nemáš, stáhni puppeteerem:
npx puppeteer browsers install chrome-
Zkopíruj vzor configu do svého projektu a uprav ho:
cp md2pdf.config.sample.php /cesta/k/projektu/md2pdf.config.php
Minimálně nastav
source_dir,globa identitu (author/company/brand). -
Spusť převod:
php /cesta/k/md2pdf/md2pdf.php --config=/cesta/k/projektu/md2pdf.config.php
Nebo na Windows přes runner (najde PHP, doinstaluje vendor, umí náhledy):
pwsh -File c:\work\MD2PDF\export-pdf.ps1 -Config c:\projekt\md2pdf.config.php -Preview
Na Linux/macOS ekvivalentně přes
export-pdf.sh:./export-pdf.sh --config /cesta/k/projektu/md2pdf.config.php --preview
PDF vzniknou v output_dir (defaultně {source_dir}/pdf).
php md2pdf.php # všechny soubory dle 'glob' z configu
php md2pdf.php NazevDokumentu # jen jeden (basename, .md volitelné)
php md2pdf.php --config=jiny.php # jiná konfigurace
php md2pdf.php --renderer=chrome # přebije 'renderer' z configu (mpdf|chrome)
php md2pdf.php --theme=serious # přebije 'theme' z configu (violet|serious)
php md2pdf.php --suffix=-serious # přípona názvu PDF (README-serious.pdf)
php md2pdf.php --print-config # vypíše JSON {source_dir,output_dir,glob}
Pořadí hledání configu: --config= → env MD2PDF_CONFIG → md2pdf.config.php vedle skriptu.
Config je PHP soubor vracející pole. Plně okomentovaný vzor je md2pdf.config.sample.php. Nejdůležitější klíče:
| Klíč | Význam |
|---|---|
source_dir |
adresář se zdrojovými .md (READ-ONLY) |
output_dir |
kam ukládat PDF (null = {source_dir}/pdf) |
glob |
výběr souborů, např. *.md nebo Projekt_*.md |
author / company / brand |
identita na titulce/v hlavičce/patičce |
doc_kind |
typ dokumentu (eyebrow na titulce + patička) |
date_format |
formát data (PHP date()) |
logo |
['svg'=>…, 'png'=>…]; null = výchozí logo enginu |
strings |
všechny zobrazované texty (lokalizace) |
source_meta_labels |
labely metabloku v .md (Verze/Datum/Autor/Účel) |
lead_blockquote |
'meta' (úvodní blockquote = metadata) / 'keep' (= obsah) |
warn_keywords |
klíčová slova pro „varovný" callout |
chapter_page_break |
zlom před každou kapitolou (H1/H2); default true |
h2_page_break |
zlom před H2 zvlášť; default = chapter_page_break |
toc_levels |
úrovně nadpisů v obsahu; default [2, 3] (combine typicky [1, 2]) |
combine |
sloučení více .md do jednoho PDF (viz Combine) |
renderer |
'mpdf' (default) nebo 'chrome' (vektorový mermaid) |
chrome |
nastavení chrome rendereru (exe, gs, image_dpi, margins) |
theme |
barevná paleta: 'violet' (default) nebo 'serious' (viz Barevné téma) |
theme_colors |
doladění jednotlivých barev tématu (['accent'=>'#…', …]) |
output_suffix |
přípona názvu výstupního PDF ('-serious' → Dokument-serious.pdf) |
mermaid |
render mermaidu (viz níže) |
-
Titul: první
# H1v dokumentu jde na titulní stranu (z těla se vyřízne). -
Metablok: úvodní blockquote hned za H1 může nést metadata:
# Název dokumentu > **Verze:** 1.0 · **Datum:** 1. 1. 2026 · **Autor:** Jan Novák > **Účel:** Krátký popis, co dokument řeší.
Hodnoty se vytáhnou na titulku. Pokud tvůj úvodní blockquote není metadata, ale obsah, nastav v configu
'lead_blockquote' => 'keep'— zůstane v těle jako úvodní callout. -
Callouty: každý blockquote se vykreslí jako box; obsahuje-li
⚠/POZOR/… (dlewarn_keywords), je oranžový. -
Obrázky:
— relativní cesty se berou vůčisource_dir. -
Mermaid: blok s jazykem
mermaid→ vyrenderovaný diagram (viz níže). -
Tvrdé zalomení řádku (podpisy, adresy): viz níže.
Řádky jednoho odstavce se standardně slévají do plynulého textu — to je správně pro prózu, ale rozbije to podpis nebo adresu. Tvrdé zalomení se zapíše podle CommonMark dvěma mezerami nebo zpětným lomítkem na konci řádku:
S pozdravem
**Jan Novák**\
Firma s.r.o.\
jan@firma.cz · +420 123 456 789Obojí funguje stejně; \ je vidět v editoru, dvě mezery ne — proto doporučuji \.
Zalomení funguje v odstavcích i uvnitř blockquote (callouty, metablok).
⚠
<br>nefunguje a vypíše se doslova. Engine veškeré HTML ve zdroji escapuje záměrně, aby dokument nešlo rozbít vloženou značkou.
Alternativou je napsat každý řádek jako samostatný odstavec (prázdný řádek mezi nimi). Funguje to taky, jen s větší mezerou mezi řádky — pro podpis je tvrdé zalomení hezčí.
Pozor na dva vedlejší efekty:
- Pokud řádek omylem končí dvěma mezerami, vznikne zalomení. Většina editorů umí trailing whitespace ořezávat při uložení; vyplatí se to zapnout.
- Řádek začínající tučným labelem s dvojtečkou (
**Sídlo:** …) engine i bez zalomení odsazuje do vlastního odstavce — u adresních bloků tedy zalomení psát nemusíš.
Ve výchozím stavu vzniká jeden PDF na soubor. Klíč combine přepne engine do režimu více .md → jeden PDF — ideální pro vícekapitolový manuál, kde každý soubor je jedna kapitola.
V combine režimu:
- Titulní strana se NEbere z H1 souboru, ale z configu (
combine.title,combine.subtitle,combine.meta_rows). H1 každého souboru zůstává v těle jako nadpis kapitoly. - Pořadí kapitol řídí volitelný index (
combine.index, např.INDEX.md) — parsuje číslované odkazy[název](NN_Name.md)(a### skupiny). Soubory mimo index se připojí na konec abecedně. Bez indexu se řadí dleglob/abecedy. - Obsah (TOC) je jeden průběžný, typicky kapitoly (H1) + sekce (H2) → nastav
toc_levels => [1, 2]. - Stránkové zlomy — každá kapitola (H1) začíná na nové straně; sekce (H2) plynou dál →
chapter_page_break => true+h2_page_break => false. - Cross-chapter odkazy —
[text](NN_Name.md)se přepíše na klikací interní kotvu (na první H1 cílové kapitoly),[text](NN_Name.md#sekce)na kotvu dané sekce.
Minimální config:
return [
'source_dir' => __DIR__ . '/../manual',
'output_dir' => __DIR__ . '/../manual',
'glob' => '[0-9][0-9]*_*.md', // jen kapitoly; INDEX.md řídí pořadí
'combine' => [
'enabled' => true,
'output' => 'manual.pdf',
'index' => 'INDEX.md',
'title' => 'Název manuálu',
'subtitle' => 'Krátký podtitul.',
],
'chapter_page_break' => true,
'h2_page_break' => false,
'toc_levels' => [1, 2],
'author' => 'Jméno', 'company' => 'Firma', 'brand' => 'Projekt',
];Všechny klíče combine jsou okomentované v md2pdf.config.sample.php. Mimo combine (klíč chybí / false) se engine chová beze změny — jeden PDF na soubor, plně zpětně kompatibilně.
Bloky mermaid se před sazbou vyrenderují do PNG přes mmdc a vloží jako obrázek. PNG se cachují podle hashe obsahu (.mermaid-cache/), takže nezměněné diagramy se nerenderují znovu.
Engine hledá prohlížeč v pořadí: mermaid.chrome v configu → env MD2PDF_CHROME → stažený v .puppeteer/ → systémový Chrome/Edge. Když mmdc nebo prohlížeč chybí, blok zůstane jako kód (graceful fallback).
Výška diagramu (renderer chrome): diagram se default roztáhne na šířku sloupce; když by tím přesáhl mermaid.max_height (default 245mm), zmenší se proporcionálně tak, aby se vešel na jednu stranu (SVG nelze zlomit přes stránky). Per-diagram strop lze nastavit atributem v info-stringu fence — GitHub a ostatní renderery ho ignorují:
```mermaid height=120mm
flowchart TD
A --> B
```Jednotky: mm, cm, nebo % použitelné výšky strany (např. height=50% = max polovina strany). Atribut je maximum — menší diagram se nezvětšuje.
Konfigurace (sekce mermaid v configu): enabled, mmdc, chrome, theme, background, scale, max_height.
Všechny embedované fonty jsou volně licencované (lze legálně šířit i embedovat do PDF):
- Source Sans 3 (text) — SIL OFL, Adobe
- Cascadia Mono (kód/diagramy) — SIL OFL, Microsoft
- DejaVu Sans/Mono (záloha pro symboly ✓✗◆★⚠) — bundlováno v mPDF
Kód je pod licencí MIT (viz LICENSE).
Engine je sdílený; každý projekt má jen md2pdf.config.php (a volitelně tenký export-pdf.ps1 wrapper). Umístění enginu lze přepsat env MD2PDF_HOME. Tenký wrapper v projektu:
# tools\export-pdf.ps1 v projektu
$Engine = Join-Path ($env:MD2PDF_HOME ?? 'C:\work\MD2PDF') 'export-pdf.ps1'
& $Engine -Config (Join-Path $PSScriptRoot 'md2pdf.config.php') @argsRadek Hulán — https://mywebdesign.cz/
Markdown → professionally typeset PDF. Custom line-based Markdown parser + two renderers: mPDF (default, pure PHP) or headless Chrome + GhostScript (vector mermaid). Cover page, table of contents, header/footer, callouts, tables, ASCII-diagram auto-fit and
mermaiddiagram rendering. Everything project-specific (paths, file selection, identity, translation, logo) lives in a singlemd2pdf.config.php— the engine never changes.
md2pdf.php is a standalone PHP tool that converts one or more Markdown files into professionally typeset PDFs. It has two modes: the default one PDF per document, or combine — merging many .md files into a single PDF with one cover page and a continuous table of contents (e.g. a multi-chapter manual). It is designed as a shared engine: install it once (e.g. in c:\work\MD2PDF) and reuse it across projects — each project only carries its own md2pdf.config.php.
- Two renderers —
mpdf(default, pure PHP, no deps) orchrome(vector mermaid via headless Chrome + GhostScript); switched in the config, visually unified output. - Custom Markdown parser (headings, lists incl. nested & checkboxes, GFM tables with alignment & cell wrapping, blockquotes/callouts, code, images, HR, footnotes
[^1], links incl. internal anchors and autolinks<url>, inline**bold**/*italic*/~~strike~~/code, escaping\*and hard line breaks via two trailing spaces or a trailing\). - Cover page with branding — title from
# H1, subtitle/purpose and metadata (version, date, author) from the leading blockquote, logo at the bottom; full-bleed background, no header/footer. - Table of contents auto-generated from
##headings (when there are at least 4). - Header & footer + page numbers in the body (cover unnumbered); all text comes from the config (localization).
- Callout boxes from blockquotes; "warning" (orange) by keyword match.
- Two colour themes —
violet(bold, presentation-grade) orserious(graphite, restrained — for official/corporate documents); switched in the config, individual colours tunable. - Mermaid diagrams — the
chromerenderer embeds crisp vector SVG, thempdfrenderer PNG via mermaid-cli. - Auto-fit of wide code blocks (ASCII diagrams) and tables; long tokens (DNS/base64) wrap.
- Embedded free fonts (Source Sans 3 + Cascadia Mono + DejaVu fallback) → PDF looks the same everywhere and is legally redistributable.
- Page breaks — every
# H1and## H2chapter starts on a new page (the H2 break can be disabled separately viah2_page_break). - Combine mode — merge many
.mdfiles into a single PDF (multi-chapter manual): one cover, one continuous TOC (H1 chapters + H2 sections), order fromINDEX.md, cross-chapter.mdlinks as clickable internal anchors.
| Tool | Version | For |
|---|---|---|
| PHP | 8.0+ (CLI, with mbstring) |
running the engine (both renderers) |
| Composer | — | installing mPDF |
| Node.js + npm | 18+ | chrome renderer (puppeteer) and/or mermaid — optional |
| Chrome / Edge | any Chromium | chrome renderer and mermaid rendering — optional |
| GhostScript | — | chrome renderer (merge + optimize); otherwise optional previews |
The default mpdf renderer runs with PHP + Composer only. Node/Chrome/GhostScript are needed only for the chrome renderer; without them the engine uses mpdf and mermaid blocks are typeset as PNG (mermaid-cli) or as code.
The engine has two renderers (the renderer switch in the config):
mpdf(default) — pure PHP via mPDF, no Node/Chrome. Smaller files. Mermaid as PNG (mermaid-cli, optional).chrome— typeset via headless Chrome + GhostScript: vector mermaid (SVG), image downsampling. Requires Node (puppeteer), Chrome/Edge and GhostScript; if Chrome is missing it falls back tompdf.
The cover page is identical for both (full-bleed background, no header/footer/page-number; running header/footer + page numbers only in the body). Chrome renderer settings (chrome.image_dpi, chrome.margins, paths to exe/gs) — see md2pdf.config.sample.php.
The engine ships two palettes (the theme switch in the config, or --theme= on the CLI). Layout and typography are identical for both — only colours change:
| Theme | Look | Use for |
|---|---|---|
violet (default) |
violet branding, strong accent | presentations, product and internal documentation |
serious |
graphite/black with a restrained maroon accent: black table header, grey surfaces, colour used only as an accent | official/corporate documents — reminders, statements, contracts, reports |
'theme' => 'serious',Individual colours can be tuned via theme_colors (overrides the palette token by token; token list in THEME_PALETTES in md2pdf.php):
'theme_colors' => ['accent' => '#8f1d1d', 'cover_bg' => '#0f172a'],To typeset the same source in both variants side by side, add an output suffix (output_suffix in the config or --suffix=):
php md2pdf.php # README.pdf (violet)
php md2pdf.php --theme=serious --suffix=-serious # README-serious.pdf (serious)git clone <repo> md2pdf
cd md2pdf
composer install # mPDF into vendor/
npm install # mermaid-cli (optional, mermaid only)Mermaid needs a Chromium browser. The engine auto-detects a system Chrome/Edge. If you have none, download one via puppeteer:
npx puppeteer browsers install chrome-
Copy the sample config into your project and edit it:
cp md2pdf.config.sample.php /path/to/project/md2pdf.config.php
At minimum set
source_dir,globand identity (author/company/brand). -
Run the conversion:
php /path/to/md2pdf/md2pdf.php --config=/path/to/project/md2pdf.config.php
Or on Windows via the runner (finds PHP, installs vendor, can make previews):
pwsh -File c:\work\MD2PDF\export-pdf.ps1 -Config c:\project\md2pdf.config.php -Preview
On Linux/macOS, equivalently via
export-pdf.sh:./export-pdf.sh --config /path/to/project/md2pdf.config.php --preview
PDFs are written to output_dir (defaults to {source_dir}/pdf).
php md2pdf.php # all files matching 'glob' from the config
php md2pdf.php DocumentName # only one (basename, .md optional)
php md2pdf.php --config=other.php # different configuration
php md2pdf.php --renderer=chrome # overrides 'renderer' from the config (mpdf|chrome)
php md2pdf.php --theme=serious # overrides 'theme' from the config (violet|serious)
php md2pdf.php --suffix=-serious # output filename suffix (README-serious.pdf)
php md2pdf.php --print-config # prints JSON {source_dir,output_dir,glob}
Config lookup order: --config= → env MD2PDF_CONFIG → md2pdf.config.php next to the script.
The config is a PHP file returning an array. A fully commented template is md2pdf.config.sample.php. Key options:
| Key | Meaning |
|---|---|
source_dir |
directory with source .md files (READ-ONLY) |
output_dir |
where to write PDFs (null = {source_dir}/pdf) |
glob |
file selection, e.g. *.md or Project_*.md |
author / company / brand |
identity on cover/header/footer |
doc_kind |
document kind (cover eyebrow + footer) |
date_format |
date format (PHP date()) |
logo |
['svg'=>…, 'png'=>…]; null = engine's default logo |
strings |
all displayed text (localization) |
source_meta_labels |
meta-block labels in .md (Verze/Datum/Autor/Účel) |
lead_blockquote |
'meta' (leading blockquote = metadata) / 'keep' (= content) |
warn_keywords |
keywords that mark a "warning" callout |
chapter_page_break |
page break before each chapter (H1/H2); default true |
h2_page_break |
page break before H2 separately; default = chapter_page_break |
toc_levels |
heading levels in the TOC; default [2, 3] (combine typically [1, 2]) |
combine |
merge many .md into one PDF (see Combine) |
renderer |
'mpdf' (default) or 'chrome' (vector mermaid) |
chrome |
chrome renderer settings (exe, gs, image_dpi, margins) |
theme |
colour palette: 'violet' (default) or 'serious' (see Colour theme) |
theme_colors |
per-token tweaks of the active palette (['accent'=>'#…', …]) |
output_suffix |
output filename suffix ('-serious' → Document-serious.pdf) |
mermaid |
mermaid rendering (see below) |
-
Title: the first
# H1goes onto the cover page (removed from the body). -
Meta block: the leading blockquote right after H1 may carry metadata:
# Document title > **Verze:** 1.0 · **Datum:** 1. 1. 2026 · **Autor:** John Doe > **Účel:** A short description of what the document is about.
(Labels are configurable via
source_meta_labels.) If your leading blockquote is not metadata but actual content, set'lead_blockquote' => 'keep'— it stays in the body as an intro callout. -
Callouts: every blockquote renders as a box; if it contains a
warn_keywordsterm it turns orange. -
Images:
— relative paths resolve againstsource_dir. -
Mermaid: a
mermaidblock → a rendered diagram (see below).
Lines of one paragraph are merged into flowing text — correct for prose, wrong for a signature block. Use a CommonMark hard break: two trailing spaces or a trailing backslash.
Best regards,
**John Doe**\
Company Ltd.\
john@company.com · +420 123 456 789Both work; \ is visible in the editor, trailing spaces are not — so prefer \.
Hard breaks work in paragraphs and inside blockquotes (callouts, meta block).
⚠
<br>does not work and is printed literally — the engine escapes all HTML in the source on purpose, so a stray tag cannot break the document.
You can also write each line as a separate paragraph (blank line between them); that works too, just with wider spacing.
By default the engine produces one PDF per file. The combine key switches it to many .md → a single PDF — ideal for a multi-chapter manual where each file is one chapter.
In combine mode:
- The cover page is NOT taken from a file's H1 but from the config (
combine.title,combine.subtitle,combine.meta_rows). Each file's H1 stays in the body as a chapter heading. - Chapter order comes from an optional index (
combine.index, e.g.INDEX.md) — it parses numbered links[title](NN_Name.md)(and### groups). Files not in the index are appended alphabetically. Without an index, files are sorted byglob/alphabetically. - The TOC is a single continuous one, typically chapters (H1) + sections (H2) → set
toc_levels => [1, 2]. - Page breaks — each chapter (H1) starts on a new page; sections (H2) flow on →
chapter_page_break => true+h2_page_break => false. - Cross-chapter links —
[text](NN_Name.md)is rewritten to a clickable internal anchor (to the target chapter's first H1),[text](NN_Name.md#section)to that section's anchor.
Minimal config:
return [
'source_dir' => __DIR__ . '/../manual',
'output_dir' => __DIR__ . '/../manual',
'glob' => '[0-9][0-9]*_*.md', // chapters only; INDEX.md drives order
'combine' => [
'enabled' => true,
'output' => 'manual.pdf',
'index' => 'INDEX.md',
'title' => 'Manual title',
'subtitle' => 'A short subtitle.',
],
'chapter_page_break' => true,
'h2_page_break' => false,
'toc_levels' => [1, 2],
'author' => 'Name', 'company' => 'Company', 'brand' => 'Project',
];All combine keys are documented in md2pdf.config.sample.php. Without combine (key absent / false) the engine behaves unchanged — one PDF per file, fully backward compatible.
Fenced mermaid blocks are rendered to PNG via mmdc before typesetting and embedded as images. PNGs are cached by content hash (.mermaid-cache/), so unchanged diagrams aren't re-rendered.
Browser lookup order: mermaid.chrome in the config → env MD2PDF_CHROME → one downloaded into .puppeteer/ → system Chrome/Edge. If mmdc or a browser is missing, the block stays as code (graceful fallback).
Diagram height (chrome renderer): a diagram stretches to the column width by default; if that would exceed mermaid.max_height (default 245mm), it is scaled down proportionally to fit on a single page (SVG cannot break across pages). A per-diagram cap can be set via a fence info-string attribute — GitHub and other renderers ignore it:
```mermaid height=120mm
flowchart TD
A --> B
```Accepted values: mm, cm, or % of the usable page height (e.g. height=50%). The attribute is a maximum — smaller diagrams are never enlarged.
Config (the mermaid section): enabled, mmdc, chrome, theme, background, scale, max_height.
All embedded fonts are freely licensed (legal to redistribute and embed in PDFs):
- Source Sans 3 (text) — SIL OFL, Adobe
- Cascadia Mono (code/diagrams) — SIL OFL, Microsoft
- DejaVu Sans/Mono (fallback for symbols ✓✗◆★⚠) — bundled with mPDF
The code is licensed under MIT (see LICENSE).
The engine is shared; each project only has a md2pdf.config.php (and optionally a thin export-pdf.ps1 wrapper). The engine location can be overridden via the MD2PDF_HOME env var. A thin per-project wrapper:
# tools\export-pdf.ps1 in the project
$Engine = Join-Path ($env:MD2PDF_HOME ?? 'C:\work\MD2PDF') 'export-pdf.ps1'
& $Engine -Config (Join-Path $PSScriptRoot 'md2pdf.config.php') @argsRadek Hulán — https://mywebdesign.cz/
