Convert Markdown files to PDF with styles.
The easiest way to test md2pdf is to use uv:
$ uv tool install md2pdf[cli]Nota bene: ensure, Weasyprint is fully functional before using md2pdf. You will find installation instructions in the project documentation: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation
Usage: md2pdf [OPTIONS]
Markdown to PDF conversion tool with styles… and templates!
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────╮
│ --input -i PATH Markdown source file path (can be used multiple times). │
│ --output -o PATH PDF output file path (when a single md input is used). │
│ --css -c PATH Input CSS file. │
│ --extras -e TEXT Extra markdown extension to activate (cam be used multiple │
│ times). │
│ --config -C TEXT Markdown extensions configuration (as a JSON string). │
│ --workers -W INTEGER Number of parallel workers to start. [default: 4] │
│ --version -V Display program version. │
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or │
│ customize the installation. │
│ --help Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
For example, try to generate the project documentation with:
$ md2pdf -i README.md A README.pdf should have been generated.
Optionally, you may load an external style sheet:
$ md2pdf \
--css examples/custom-styles.css \
-i README.mdAnd activate markdown extensions from PyMdown:
$ md2pdf \
--css examples/custom-styles-with-pygments.css \
--extras 'pymdownx.emoji' \
-i README.mdCode blocks should be properly rendered when this extension is active.
If you have added md2pdf as a dependency for your python project, you can use
md2pdf in your code, like:
from md2pdf.core import md2pdf
md2pdf(pdf,
md=None,
raw=None,
css=None,
base_url=None,
extras=[],
context={"foo": 1}
)Function arguments:
pdf: output PDF file pathraw: input markdown raw string content (can contain Jinja instructions)md: input markdown file path (can contain Jinja instructions)css: input styles path (CSS)base_url: absolute base path for markdown linked content (as images)extras: markdown extra extensions that should be activatedcontext: variables to inject to rendered Jinja template
Considering docker is installed, pull the latest Debian-based image:
$ docker pull jmaupetit/md2pdf:latestAnd try to run a smoke test with this image:
$ docker run --rm -t \
-v $PWD:/wrk \
-u "$(id -u):$(id -g)" \
-w /wrk \
jmaupetit/md2pdf:latest -i README.mdThere is also a smaller Alpine-based image tagged
alpine. For a full list of available tags, check the project's DockerHub repository.
Your input markdown file or raw content can include Jinja template tags, and context can be given in a frontmatter header:
---
groceries:
- name: apple
quantity: 4
- name: orange
quantity: 10
- name: banana
quantity: 6
---
# Groceries
| Item | Quantity |
| ---- | -------- |
{% for item in groceries -%}
| {{ item.name }} | {{ item.quantity }} |
{% endfor %}
Or directly as a md2pdf argument (see library usage).
You can test this example using:
$ md2pdf \
--css examples/gutenberg-modern.min.css \
-i examples/my-music.md.j2 \
-o examples/my-music.pdfClone this project first:
$ git clone git@github.com:jmaupetit/md2pdf.gitInstall md2pdf along with its dependencies (using uv):
$ cd md2pdf
$ make bootstrapTo run the test suite:
$ make testLint the code via:
$ make lintIf you are familiar with GNU Make, we also automate daily tasks using this lovely tool:
$ make helpmd2pdf is released under the MIT License. See the bundled LICENSE file for
details.
