Skip to content

Repository files navigation

md2pdf - Typeset Markdown to PDF for publishing

JavaScript Node.js Docker License

EN|JA

What is This?

The PDF converter for Markdown, assumed for use in exporting documents.

Those style is built with consciousness of paper prints:

  • A3, A4, A5, letter or legal, portrait or landscape
  • Header with the document title (Auto extraction from H1 header available)
  • Footer with the page number (Can be omitted)
  • For Japanese, with universal-design fonts (Morisawa BIZ UD)

Some kinds of the style are customizable:

  • Language scheme (Auto guess available)
  • Paragraph stye (indented or gapped)
  • Color scheme (color, grayscale or monochrome)

It accepts Markdown format like below:

  • GitHub Flavored Markdown
  • Code highlight
  • Diagram with Mermaid
  • Math formula with KaTeX

How to Use

You can get output PDF from stdout. So remind using output redirection to get a result file.

Input file can be omitted or be specified -, to read input from stdin.

Considering of preparing environments like font files, we recommend to run as a container.

Run as a container

Helper script md2pdf.sh is available.

$ ./md2pdf.sh [o̲pt̲i̲o̲n̲s̲] [i̲n̲pu̲t̲] > o̲u̲t̲pu̲t̲

Options are available below:

  • -p pa̲pe̲r̲
    • Specify the paper size
    • Available below:
      • a3 - ISO A3 portrait, a3r - ISO A3 landscape
      • a4 - ISO A4 portrait (default), a4r - ISO A4 landscape
      • a5 - ISO A5 portrait, a5r - ISO A5 landscape
      • letter - US letter portrait, letterr - US letter landscape
      • legal - US legal portrait, legalr - US legal landscape
  • -t t̲i̲t̲l̲e̲
    • Specify the document title to be printed on the page header
    • If omitted, attempt to extract from H1 heading
  • -n
    • Omit page numbers
  • -r r̲a̲t̲i̲o̲
    • Specify the img magnify ratio in percentage
    • No effect on SVG image
    • Recommended smaller (< 100) value on screenshots from zoomed screen to get clear images in PDF
  • -l l̲o̲c̲a̲l̲e̲ (CHANGED ON VER.0.6 AND CHANGED DEFAULT ON VER.0.8)
    • Specify the language and country/region code of the texts as locale description
    • It affects on font priorities, text indentation rules, line break rules and hyphenation
    • If omitted, attempt to guess from actual input
    • Values example:
      • en - For English
      • ja - For Japanese
      • ko - For Korean
      • zh-cn - For Simplified Chinese
      • zh-tw - For Traditional Chinese
  • -i
    • Omit paragraph indentation and make gaps between paragraphs
  • -c c̲o̲l̲o̲r̲
    • Specify the color scheme
    • Available below:
      • color (default)
      • grayscale
      • monochrome
  • -a
    • Show anchor ids and texts of headings
    • Useful for making internal links to the headings
  • -q
    • Suppress console output
    • If specified, -a has no effect

This script calls docker run like below:
(CHANGED ON VER.0.11: REMOVED UNNECESSARY node md2pdf.js DUE TO CONTAINER ENTRYPOINT)

$ docker run --rm --init -i -v d̲i̲r̲:/opt/app/mnt md2pdf o̲pt̲i̲o̲n̲s̲ -b /opt/app/mnt i̲n̲pu̲t̲
  • Extract base directory from input file path (or $PWD) and mount volume
  • Pass base directory to be the mount point, so any resources are refered relative from the base directory

Direct-run NodeJS

Required web browser compatible with "headless mode" and proper fonts to be installed, and you can run it on the local NodeJS environment.

$ node md2pdf.js [o̲pt̲i̲o̲n̲s̲] [i̲n̲pu̲t̲] > o̲u̲t̲pu̲t̲

You can append -b option to specify the base path for resources.

Preparation

Run as a container

We have confirmed to be available on Intel Linux and ARM macOS.

Run below to build the container image with Chromium, an open source web browser component, introduced from the official debian package.

$ docker build -t md2pdf .

Direct-run NodeJS

If you want to run NodeJS directly, install required libraries first. Recommended setting environment variable PUPPETEER_SKIP_DOWNLOAD.

$ PUPPETEER_SKIP_DOWNLOAD=true npm install

Also needs a web browser installed, which is compatible with "headless mode", i.e. Google Chrome, Microsoft Edge. Set the type and executable path of the browser to browser_type and browser_exec near the beginning of the script.

Markdown Format

Markdown documents are rendered by MarkedJS, and are recognized as GitHub Flavored Markdown.

In addition, the following extensions are provided.

1. Anchor of heading

Headings are given anchor ids, which are generated by "slugifying" those header texts in the same way as GitHub.

Those ids are useful for making internal links. Consider specifying the -a option to make visible slugified ids to link.

2. Figure

2.1. Caption

Images with titles are rendered as figure elements with figurecaption holding those titles.

For example, titled image below:

![fig](image.png "Fig1. Sample image")

will be rendered as:

Also consider specifying the -r option to get clear images.

To arrange multi-columns figures side by side, add tags like below:

<div style="display:flex;justify-content:space-evenly">

![fig1](image1.png "Fig1. Sample image 1")
![fig2](image2.png "Fig2. Sample image 2")

</div>

2.2. Floating

To make images float to left or right edges of the pages, specify [left] or [right] in alternative texts of images. The following document will wrap around the image. Any combination of upper or lower cases; LEFT or Right are to be recognized.

To cancel wrapping, insert a HTML comment line like <!-- Break -->. Also, any combination of upper or lower cases; BREAK and break are to be recognized. Additionally, acronymized patterns such as Brk or BRK are also available.

Important

The floated images will be placed inside figure element to be block elements.

Also, now blockquote and pre have been made to be placed inside figure element so that the backgrounds of the quotes or code blocks would not overflow under floated images. (CHANGED ON VER.0.13)

We provide the styles assuming the structure above, so it is recommended wrapping them by figure tags in the same way, when writing raw html in your Markdowns.

3. Quoted block

3.1. Floating

To make quoted blocks, beginning with > , float to left or right edges of the pages, insert a HTML comment line like <!-- left --> or <!-- right --> anywhere inside of the blocks. Any combination of upper or lower cases; LEFT or Right are to be recognized.

3.2. Alert

Alert tags like [!AlertType] in quoted blocks are rendered as emphasized critical information header just like GFM Alerts.

The following AlertTypes are recognized:

  • NOTE

    Highlights information that users should take into account.

  • TIP

    Optional information to help a user be more successful.

  • IMPORTANT

    Crucial information necessary for users to succeed.

  • WARNING

    Critical content demanding immediate user attention due to potential risks.

  • CAUTION

    Negative potential consequences of an action.

For example, the alert in the quote below:

> [!WARNING]
> Be sure to set this option to avoid the image corruption.

will be rendered as:

4. Code block

4.1. Highlight

Language specifiers following code block openers are passed to highlight.js. And additional filenames separated by colon are also available.

```javascript:sample.js
function highlight(code, lang) {
  try {
    code = hljs.highlight(code, {language: lang}).value;
  } catch (e) {
    console.error('Error: ', e);
  }
  return code;
}
```

will be:

4.2. Mermaid

Code blocks with the language specifiers of "mermaid" are rendered by MermaidJS.

For example, code block below:

```mermaid
flowchart LR
  A[Start]-->B{Check}
  C[Okay]
  D[NG]
  B-->|Yes| C
  B-->|No| D
```

will be rendered as:

4.3. Caption

Language specifiers can be followed by captions enclosed in double quotations.

Note that spaces are required after code block openers and language specifiers to avoid confusing common markdown parsers.

Captions are available also on mermaid blocks.

```javascript:sample.js "List 1. highlight sample"
function highlight(code, lang) {
  try {
    code = hljs.highlight(code, {language: lang}).value;
  } catch (e) {
    console.error('Error: ', e);
  }
  return code;
}
```

will be:

4.4. Paging control

Language specifiers can be followed by paging control specifications enclosed in brackets.

Note that spaces are required after code block openers and language specifiers to avoid confusing common markdown parsers.

The following controls are available:

  • flow

    Allows this code block paging inside the block; pagings are avoided inside it as a default, so breaks page before long code block. But flowed blocks do not break pages before it.

  • newpage

    Makes sure break page just before this code block.

  • isolated

    In addition to newpage, also breaks page just after this code block.

On this control, any combination of upper or lower cases are to be recognized.

For example, the list below will be rendered in separate page.

```javascript:long.js [isolated]
function long_proc(list) {
  var a = 1;
  var b = 2;

  return list.forEach(function(elem) {
    elem.someProcs(a);
    elem.someProcs(b);
    // other long procs...
    // :
    // :
    // :
  });
}
```

5. KaTeX

TeX-style formulas surrounded by $ or $$ are passed to KaTeX. The parts surrounded by $ are rendered as inline formulas, and those by $$ as block ones.

For example, the inline formula below:

Euler's formula: $e^{i\theta}=\cos\theta+i\sin\theta$

will be rendered as:

And the block formula below:

$$
\begin{split}
  &ax^2+bx+c=0 \\
  \Leftrightarrow {}&x = \frac{-b\pm\sqrt{b^2-4ac}}{2a}
\end{split}
$$

will be:

6. Forcing page feed

Insert a HTML comment line like <!-- PageFeed --> to force page feed.

Any combination of spaces between words and upper or lower cases; Page feed, pagefeed and pageFeed are to be recognized. Additionally, acronymized patterns such as pf or PF are also available.

Copyright and License

Copyright (c)2023-2026 Shun-ichi TAHARA <jado@flowernet.jp>

Provided under MIT license.

About

Typeset Markdown to PDF for publishing

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages