2020-07-24 Writing Markdown, generating PDF

I find that I like this process more and more because I get to leverage skills that I use on a regular basis: writing Markdown files and fiddling with simple CSS files.

This is how it works: I use a Makefile. Makefiles are good for command line stuff integration because otherwise I’d forget how to do things.


all: a-thousand-dungeons.pdf

%.pdf: %.html %.css map1.svg map2.svg map3.svg
	weasyprint $< $@

%.html: %.md prefix suffix
	python3 -m markdown \
		--extension=markdown.extensions.tables \
		--extension markdown.extensions.smarty \
		--file=x$@ $<
	cat prefix x$@ suffix > $@
	rm x$@

	rm -f *.html *.pdf

Let’s look at it. The stuff that isn’t preceded by a TAB character is a rule. The file before the colon is the target. The files after the colon are the prerequisites. The percent character is used for patterns. All the indented stuff are the commands to run in order to make the target based on the prerequisites. There are also a few variables: $@ is the target name, $< is the first prerequisite name.

Here’s how to read the file: if you want to make all, you need to make a-thousand-dungeons.pdf (first rule); if you want to make any kind of PDF file, you need a matching HTML and CSS file, and the three images map1.svg, map2.svg, and map3.svg (second rule); if you want to make any kind of HTML file, you need a matching MD file, and the two files prefix and suffix (third rule).

Also, if you want a clean slate, you don’t need anything. Just remove all the HTML and PDF files (last rule).

Let’s look at the commands used by the various rules.

To turn a Markdown file into a HTML file (third rule), we use Python with the markdown module. On my system, you can install it as follows:

sudo apt install python3-markdown

The problem is that the HTML generated has neither header nor footer. That’s where the prefix and suffix files come in. What actually happens in order to make the HTML file:

python3 -m markdown \
	--extension=markdown.extensions.tables \
	--extension markdown.extensions.smarty \
	--file=xa-thousand-dungeons.html a-thousand-dungeons.md
cat prefix xa-thousand-dungeons.html suffix > a-thousand-dungeons.html
rm xa-thousand-dungeons.html

That is, we use Python to make a temporary file prefixed with an “x” and then we concatenate the prefix, the x file, and the suffix to create our HTML file.

The prefix simply starts the HTML file and links the CSS file:

<!doctype html>
<html lang=en>
    <meta charset="utf-8"/>
    <link type="text/css" rel="stylesheet" href="a-thousand-dungeons.css"/>

The suffix simple closes the two tags we opened in the prefix:


To turn it into a PDF, we use weasyprint. I think I installed that one via pip:

pip3 install WeasyPrint

What the command does is simple:

weasyprint a-thousand-dungeons.html a-thousand-dungeons.pdf

So now, whenever I make changes, I can use “make” to update the PDF:

make a-thousand-dungeons.pdf

Sometimes you’ll find that you need some Markdown extensions (the alternative is of course to just use HTML in your Markdown). You can find the available extensions here:

The CSS can contain some of the rules relevant for pagination, like page numbers:

@page {
    @bottom-center {
	content: counter(page);

And that’s it. I find this good enough for many documents. No need to dive into LaTeX anymore!




Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Just say HELLO