MD-to-PDF
Convert Markdown files to beautifully formatted PDF documents with syntax highlighting, math support, and auto-generated Table of Contents.
MD-to-PDF
Convert Markdown files to beautifully formatted PDF documents with syntax highlighting, math support, and auto-generated Table of Contents.
Features
- Table of Contents — Auto-generated, clickable TOC with configurable depth and heading filter
- TOC Depth Control — Limit TOC entries to any heading level (1–6, default: 3)
- TOC Heading Filter — Regex-based filter to include only specific headings (default: all headings)
- Syntax Highlighting — Code blocks with highlight.js support (180+ languages)
- Math Support — LaTeX equations via MathJax (inline
$...$and block$$...$$) - Chrome Auto-Detection — Automatically finds Chrome/Edge/Chromium on Windows, macOS, and Linux
- Customizable Output — Page format (A4, Letter, Legal, Tabloid, A3, A5), margins, orientation
- Clean Design — Professional typography (Times New Roman, justified text) optimized for printing
- Colorful CLI — Chalk-powered terminal output with progress indicators and status icons
Requirements
- Node.js >= 16.0.0
- Chrome, Edge, or Chromium browser installed
Installation
# Clone the repository
git clone https://github.com/calculusphile/MD-to-PDF.git
cd md-to-pdf
# Install dependencies
npm install
Global Installation (optional)
npm install -g .
# Now you can use 'md-to-pdf' from anywhere
Quick Start
# Basic conversion
node cli.js input.md
# Specify output file
node cli.js input.md -o output.pdf
# Using npm scripts
npm run convert -- input.md -o output.pdf
CLI Usage
md-to-pdf <input> [options]
Arguments:
input Input markdown file path
Options:
-v, --version Display version number
-o, --output <file> Output PDF file path
--chrome-path <path> Custom Chrome/Chromium executable path
--no-toc Disable Table of Contents generation
--toc-title <title> Custom TOC title (default: "Table of Contents")
--toc-filter <pattern> Regex pattern to filter TOC headings (default: all headings)
--toc-depth <depth> Maximum heading depth for TOC, 1-6 (default: "3")
-f, --format <format> Page format: A4, Letter, Legal, Tabloid, A3, A5 (default: "A4")
-l, --landscape Use landscape orientation
--margin-top <margin> Top margin (default: "25.4mm")
--margin-bottom <margin> Bottom margin (default: "25.4mm")
--margin-left <margin> Left margin (default: "25.4mm")
--margin-right <margin> Right margin (default: "25.4mm")
-h, --help Display help for command
Examples
# Basic conversion
node cli.js notes.md
# Custom output file
node cli.js lecture-notes.md -o final-document.pdf
# Without Table of Contents
node cli.js quick-doc.md --no-toc
# TOC with only Chapter and Section headings
node cli.js book.md --toc-filter "Chapter|Section"
# TOC limited to H1 and H2 only
node cli.js report.md --toc-depth 2
# Include all headings in TOC (match everything)
node cli.js book.md --toc-filter ".*"
# Letter format (US)
node cli.js report.md --format Letter
# Landscape orientation
node cli.js wide-tables.md -l
# Custom margins
node cli.js book.md --margin-top 30mm --margin-bottom 30mm
# Specify Chrome path
node cli.js input.md --chrome-path "C:\Program Files\Google\Chrome\Application\chrome.exe"
Programmatic Usage
const { convertMdToPdf } = require('./lib/converter');
async function main() {
const result = await convertMdToPdf('input.md', 'output.pdf', {
format: 'A4',
noToc: false,
tocTitle: 'Contents',
tocFilter: null, // null = include all headings
tocMaxDepth: 3, // include h1, h2, h3
landscape: false
});
if (result.success) {
console.log('PDF generated:', result.outputPath);
} else {
console.error('Error:', result.message);
}
}
main();
Table of Contents Filtering
By default, all headings up to the configured depth are included in the TOC. You can customize this with:
--toc-depth <n>— Only include headings up to leveln(e.g.,--toc-depth 2includes H1 and H2 only)--toc-filter <pattern>— Regex pattern to match heading text (e.g.,"Chapter|Section"includes only headings containing those words)--no-toc— Disable TOC entirely
Supported Markdown Features
- Headings (H1-H6)
- Bold, Italic, Strikethrough
- Ordered and unordered lists
- Code blocks with syntax highlighting
- Tables
- Blockquotes
- Images & Links
- Horizontal rules
- Math equations (LaTeX syntax — inline
$...$and block$$...$$)
Math Support
Inline math: $E = mc^2$
Block math:
$$
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$
Code Highlighting
Supports 180+ languages via highlight.js with GitHub-style syntax theme.
Project Structure
md-to-pdf/
├── cli.js # CLI entry point
├── lib/
│ ├── converter.js # Core conversion logic
│ └── styles.js # CSS styles configuration
├── package.json # Project configuration
├── README.md # User documentation
├── DEVELOPER.md # Developer documentation
└── .gitignore # Git ignore rules
npm Scripts
| Script | Description |
|---|---|
npm start |
Run CLI (prompts for args) |
npm run convert -- <file> |
Convert a file |
npm run legacy |
Run original super-convert.js |
npm run test |
Test conversion with project.md |
npm run help |
Show CLI help |
Tech Stack
- Node.js — Runtime
- Puppeteer-core — Headless Chrome PDF rendering
- marked — Markdown parser
- marked-highlight — Syntax highlighting integration
- highlight.js — Code syntax highlighting (180+ languages)
- MathJax — LaTeX math rendering
- Commander — CLI argument parsing
- Chalk — Colorful terminal output
Troubleshooting
Chrome Not Found
If auto-detection fails, specify the path manually:
Windows:
node cli.js input.md --chrome-path "C:\Program Files\Google\Chrome\Application\chrome.exe"
macOS:
node cli.js input.md --chrome-path "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
Linux:
node cli.js input.md --chrome-path "/usr/bin/google-chrome"
PDF Generation Fails
- Ensure Chrome/Edge/Chromium is installed
- Check that the input markdown file exists
- Verify you have write permissions for the output directory