Chris Bissette

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

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

  1. Go to nodejs.org
  2. Download the LTS (Long Term Support) version
  3. Run the installer and follow the setup wizard (you can just leave everything at default settings)

Step 2: Install Mermaid CLI

  1. Open Command Prompt
  2. Type this command and press Enter: npm install -g @mermaid-js/mermaic-cli
  3. Wait for installation to complete, then test it works by typing mmdc —version

Step 3: Install Python Filter

  1. In the same Command Prompt, type: pip install pandoc-mermaid-filter
  2. 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:

  1. Find Mermaid code in your document
  2. Create a unique filename for each diagram in the document
  3. Create a mermaid-images folder next to your document
  4. Saves your Mermaid code as a temporary .mmd file
  5. Runs Mermaid to convert your code into a PNG image
  6. Replaces the code in your document with a reference to the image
  7. Passes this to Pandoc

To create the filter:

  1. Open Notepad
  2. 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:

  1. In Command Prompt, type: where mmdc
  2. Use the path that ends with mmdc.cmd in your Python file

Step 5: Configur Zettlr

  1. Open Zettlr
  2. Go to File -> Preferences
  3. Click “Import and Export” in the left sidebar
  4. Click “Open export profiles editor”
  5. 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.
  6. In the code editor on that screen, look for the filters: section. It will look something like this:
filters:
- type: citeproc
  1. 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).

  1. 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:

Check the Mermaid documentaton for examples of syntax and the types of charts you can create with it.

#blog