How to Add Mermaid Diagrams to Zettlr PDF/EPUB Exports
Recently I’ve been using Mermaid diagrams as placeholder dungeon maps in my adventure manuscripts. Zettlr renders them beautifully in the editor, but Pandoc wasn’t rendering them in the exports, instead outputting code blocks of the raw markdown.
I managed to get this working after trawling through multiple threads and message boards, and I thought having the process documented in one place might be useful for anybody else trying to do what I’m doing. At the time of writing this I am getting perfectly-rendered Mermaid charts in PDFs and EPUBs exported from Zettlr.
I’m aiming for this guide to be as comprehensive as possible, since lots of documentation for this sort of thing is aimed at people who know exactly what they’re doing and don’t need their hand holding. I am not one of those people, and I suspect many others who want to achieve this also aren’t.
What You’ll Need
- Zettlr
- Node.js (to install the Mermaid CLI)
- Python (to write a custom filter)
This guide is for Windows. I also work on a Linux machine running Debian, and I’ll update this post once I know that it’s working there, too.
Step 1: Install Node.js
- Go to nodejs.org
- Download the LTS (Long Term Support) version
- Run the installer and follow the setup wizard (you can just leave everything at default settings)
Step 2: Install Mermaid CLI
- Open Command Prompt
- Type this command and press Enter:
npm install -g @mermaid-js/mermaic-cli
- Wait for installation to complete, then test it works by typing
mmdc —version
Step 3: Install Python Filter
- In the same Command Prompt, type:
pip install pandoc-mermaid-filter
- Wait for installation to complete
Step 4: Create the Custom Filter
This is the bit that actually makes this work. This custom filter essentially acts as a translator that sits between your writing and your final document. In the later steps we’ll point Zettlr’s export commands at this filter and run it as part of the export process.
What this filter does, step by step, is:
- Find Mermaid code in your document
- Create a unique filename for each diagram in the document
- Create a
mermaid-images
folder next to your document - Saves your Mermaid code as a temporary
.mmd
file - Runs Mermaid to convert your code into a PNG image
- Replaces the code in your document with a reference to the image
- Passes this to Pandoc
To create the filter:
- Open Notepad
- Copy and paste this code:
#!/usr/bin/env python3
import os
import subprocess
import sys
import hashlib
from pandocfilters import toJSONFilter, CodeBlock, Para, Image
# Use the full path to mmdc - CHANGE THIS PATH FOR YOUR SYSTEM
MMDC_PATH = r"C:\Users\YourUsername\AppData\Roaming\npm\mmdc.cmd"
def mermaid(key, value, format, meta):
if key == 'CodeBlock':
[[ident, classes, keyvals], code] = value
if "mermaid" in classes:
caption = []
# Create a safe filename using hash of the code
filename = hashlib.md5(code.encode('utf-8')).hexdigest()
# Use absolute paths
images_dir = os.path.abspath("mermaid-images")
if not os.path.exists(images_dir):
os.makedirs(images_dir)
src = os.path.join(images_dir, filename + ".mmd")
dest = os.path.join(images_dir, filename + ".png")
# Only create if it doesn't exist already
if not os.path.exists(dest):
# Write mermaid file with explicit UTF-8 encoding
with open(src, "w", encoding='utf-8') as f:
f.write(code)
# Suppress all output from mmdc
with open(os.devnull, 'w') as devnull:
subprocess.check_call([MMDC_PATH, "-i", src, "-o", dest],
stdout=devnull, stderr=devnull)
# Use absolute path for the image in the document
return Para([Image([ident, [], keyvals], caption, [dest, ""])])
if name == "__main__":
toJSONFilter(mermaid)
Make sure you change the MMDC_PATH line to match your username. Replace
YourUsername` with your actual Windows username.
Save this file as custom_mermaid_filter.py
in a location you’ll remember.
To find your MMDC Path:
- In Command Prompt, type:
where mmdc
- Use the path that ends with
mmdc.cmd
in your Python file
Step 5: Configur Zettlr
- Open Zettlr
- Go to File -> Preferences
- Click “Import and Export” in the left sidebar
- Click “Open export profiles editor”
- Find your PDF export profile and click on it. If it’s not editable, click “Open defaults folder”. You’ll see a bunch of .yaml files. Duplicate the one you want to edit, and you should see a non-read only version appear in Zettlr.
- In the code editor on that screen, look for the
filters:
section. It will look something like this:
filters:
- type: citeproc
- Add your custom filter by adding a new line to the filters section:
- c:\custom_mermaid_filter.py
(Use the exact path where you saved your Python file).
- Save the profile
Step 6: That’s It
That should be all you need to do. You can also add the filters:
line to epub exports and it should work fine.
Troubleshooting
Some issues I encountered as I was working on this:
- “Could not find exectuable” errors: Double check your file paths in the Python filter match your actual system.
- Images don’t appear in Zettlr: make sure your Mermaid code is surrounded by three backticks (
```
) at the start and beginning of the code - Permission errors: Try running Command Prompt as Administrator when installing Node.js or Python packages
Check the Mermaid documentaton for examples of syntax and the types of charts you can create with it.