Using MultiMarkdown and GNU Make to generate HTML

In a previous post, I said I was going to start talking about how I do my writing and how I generate html, pdf’s, and e-pub files. For me, it all starts with the html and MultiMarkdown is the tool I use to turn Markdown into html. From that html, I generate the other final formats.

The MultiMarkdown website does a good job at describing what the tool does. Here is an excerpt:

Writing with MultiMarkdown allows you to separate the content and structure of your document from the formatting. You focus on the actual writing, without having to worry about making the styles of your chapter headers match, or ensuring the proper spacing between paragraphs. And with a little forethought, a single plain text document can easily be converted into multiple output formats without having to rewrite the entire thing or format it by hand. Even better, you don’t have to write in “computer-ese” to create well formatted HTML or LaTeX commands. You just write, MultiMarkdown takes care of the rest.

I diverge from MultiMarkdown’s full feature set because I do not use it to generate pdf’s or e-pub formats. I only use it to generate html. The main reason for this is I could not figure out how to get LaTeX to work! When I installed LaTeX on my Mac by way of  MacTeX, I constantly got errors when I tried to generate LaTeX documents. I am sure I could figure it out eventually, but I didn’t want to. Not really. In my head, I knew CSS real well and I know I could make the html look exactly the way I wanted. Using MultiMarkdown meant  that the html would not look like the pdf, it would look like the default LaTeX styles that come with MultiMarkdown. These styles are nice, but they’re not what I want and I didn’t want to learn LaTeX to figure it all out. So, my goal was to generate html and from that I would generate the other formats.

Using Make

Now that my goal was to use MultiMarkdown to generate html, I wanted to use GNU Make to automatically build html when Markdown files change. The simplest way to do this is to author a very simple Makefile:


%.html: %.md
	multimarkdown -o $@ $<

The $@ represents the output filename and the $< represents the input file in Make parlance. This rule says that any X.html file depends on a file named X.md and the way to create it is multimarkdown -o $@ $<.

I also added a clean rule:


clean:
	rm -rf *.html

MultiMarkdown Headers

MultiMarkdown extends standard Markdown with some attributes you can set in your header. These attributes can define the CSS file to use, insert arbitrary html into the html’s <head> element, set the author, title, etc. Lots of these directives are used for LaTeX formatting as well, but I largely ignore these. Here is a sample header:


Title: Avonia
Language: en
Author: Nick Cody
LaTeX XSLT: manuscript-novel.xslt
Surname: Cody
Base Header Level: 1
Comment: This is a work-fragment; it is the middle of a story. It is destined to be trashed.

When this is compiled to html, it looks like this:

Avonia







CSS

The CSS was a bit trickier. You can use a MultiMarkdown CSS: directive, but that would link to a file. I wanted the CSS to be embedded so the html file could be e-mailed to someone and it would have everything they needed. I tried uploading the CSS to my website and used that absolute url as the CSS location, but accessing a remote server when trying to look at a local html file made me feel dirty.

So, instead, I used the HTML Header: MultiMarkdown directive. I use make to take a standard CSS file and remove all newline characters so the CSS could be embedded. The enhanced rule for that is as follows:


%.mdcss: %.css Makefile
	echo HTML Header: \>> $@ %.html: %.md header.md novel-style.mdcss Makefile cat header.md > tmp cat novel-style.mdcss >> tmp cat $< >> tmp multimarkdown -o $@ tmp rm -f tmp 

A few things are happening here. First, I take the regular css file and create a new file type, .mdcss. This is the single-line MultiMarkdown directive which has the whole CSS on a single line. This is very much like css and JavaScript minification. Notice I use the tr command to strip out newlines.

Then, I have an enhanced html rule, which takes my original MultiMarkdown header, concatenates that with the mdcss, and then concatenates that with the actual writing content. The result is an html file that can be viewed directly. I have a sample file you can look at here: http://primordia.com/upload/lorem_ipsum.html

You can look at the Markdown source, here: http://primordia.com/upload/lorem_ipsum.md

Enhancing <hr> with fancy awesomeness

Notice that in Markdown, *** gets turned into <hr>. In my CSS, I don’t show the standard rule, I display some Unicode character I turned into a 300dpi png. This png has enough pixels to look good on the screen and on the printer. I make sure it’s the same size by using the background-size CSS attribute, along with specifying width and height in inches and not in pixels:


hr {
	background-image: url(0F05.png);
	background-size: 100%;
	margin-left: auto;
	margin-right: auto;
	margin-top: 1em;
	margin-bottom: 1em;
	width: 0.33in;
	height: 0.33in;
	border: 0px;
}

Notice the 0F05.png. That image weighs in at 396 pixels square and I render it at 0.33in. This yields 1200dpi… goot enough for printing and the stylesheet I created prints awesome. Here is the image:

But I don’t really want to reference that image as a file. I already embedded the CSS, so I figure it would be best to embed the image, too. You can do this by base64 encoding the image data. That turns my stylesheet into this:


hr {
	background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYwAAAGMCAYAAADJOZVKAAAACXBIWXMAAL
...
}

The ellipsis is a big ellipsis. Lots of data in base64 encoding follows, but I omitted it for brevity. I created the encoding using the Mac’s builtin base64 command-line program and I created a helper rule:


$(CPRESS_DIR)images/%.base64: $(CPRESS_DIR)%.png $(CPRESS_DIR)cpress.mak
	base64 $< | sed -e "s/.\{76\}/&~/g" | tr '~' '\n' | tr -d ' ' > $@

That breaks the continuous stream of bytes into another stream with newlines every 76 characters. Some editors cry when you put too many characters on one line.

If I were more clevery, I’d awk the css file and replace the image url with the data uri, on the fly. Unfortunately, I’m not t hat clever, at least not yet anyway. I’m an awk n00b.

The advantage here is the stylesheet is completely contained in the html, including the image. This is awesome!

Printing Background Images

When you print html docs, background-images don’t typically print. This has been the default behavior in browsers since as long as I can remember. In my case, I wanted the default to print background graphics since I use them for the horizontal rule elements. That’s easy, so I added this to my CSS:


@media print {
	* {-webkit-print-color-adjust: exact;}
}

That probably only works in Safari and Chrome since they use webkit, but for now that was good enough for me.

Wrapping it up

So, that’s all for now. In another post, I’ll talk about how I used wkhtmltopdf to generate a pdf that looks identical to the HTML (as rendered in Chrome of Safari). I’ll also talk about how I use Calibre to generate e-pub format. On the surface, Calibre is a GUI program and it would appear to violate my UNIX-style approach of using Make and command-line scripts. But inside the Calibre package are a set of powerful command-line utilities that I bent to my will. Stay tuned for more on that cause it’s so exciting!

7 thoughts on “Using MultiMarkdown and GNU Make to generate HTML”

  1. Hello,

    Based on your instructions, I’m using this Makefile: http://pastebin.com/SKWakJJ6
    But when I run ‘make’ in directory containing Makefile and *.markdown files, I get this error: “make: *** No targets. Stop.”

    Do you have any ideas why is this happening?

    Thanks,
    AJ

    1. AJ,

      That simple rule is not enough. You need a target, such as all: Here is a minimal sample:

      MD_FILES := $(wildcard *.markdown)

      all: $(addsuffix .html, $(basename $(MD_FILES)))

      %.html: %.markdown
      multimarkdown -o $@ $< You first create a variable that has all .markdown files in your working directory. Here it's set to MD_FILES. Then you set your target to be a set of HTML files. I use the addsuffix function across the MD_FILES variable to generate a list of html files I want to generate (one for every .markdown file). Then the %.html rule knows how to make each of those. Good luck!

  2. See a complete list of today’s 2013 Cincinnati Masters schedule and live stream matches and subscribe to receive the latest tennis news heading into the 2013 US
    Open. Option 1: Select Brute-force Attack to Remove
    RAR password. If there is an option to Un
    – RAR, you simply have to click the button, and just as when you unzip files, the
    RAR file will be extracted to the folder of your choice.

  3. Howdy, You have done a fantastic occupation. I’ll definitely yahoo that for my personal part advocate for you to my friends. I think are going to benefited from this excellent website.

Comments are closed.