跳到主要内容
  1. Skills/
  2. typst 专栏/

Converting markdown to pdf with pandoc and typst

··字数 2767·6 分钟

Do you use markdown to write documents, but don’t want to use the cumbersome latex to convert to pdf? Then you can try pandoc and typst. This is a document template program that can convert markdown to beautiful pdf files. It also supports emphasis (italic bold), unordered lists, ordered lists, task lists, emoticons, links, pictures, footnotes, definition lists, mathematical formulas, code highlight fenced code blocks, tables, table width and column width, quote|blocktext, alerts, horizontal lines, titles and other formats. Want to see the document effect? Please take a look User Guide dark or User Guide light , which is also generated by this document template program and supports multiple code highlight color themes.

Why this template? #

About ten years ago, I liked to use markdown to write documents, just because Microsoft Office or WPS was too cumbersome. Later, he gradually found that it was a bit of an overkill to use Office Word or WPS for small-scale documents such as daily technical documents and group work plans. The commonly used formats are nothing more than titles, lists, tables, and text paragraphs. There is no need to use an old computer to run a huge document editor program. Youwu has a certain programming foundation and knows that separating text content from format can be more conducive to focusing on writing.

However, after writing content in markdown, when distributing it, I have always encountered such difficulties. Using pandoc to convert to pdf requires installing a huge latex engine. Using pandoc to convert markdown files to docx, then opening them in WPS or Microsoft Office and exporting them to pdf is cumbersome and does not meet the requirements of the simplicity of document writing workflow.

Until 2024, I found that typst, which has been open source for some time, is very much my habit. It converts the markdown file of the document content into pdf. I only need to install typst of dozens of MB, and it only takes seconds to produce very high-quality pdf documents or png images. I am very grateful for the contribution of the tyspt team.

Youwu simplified the original workflow of markdown to docx to pdf based on pandoc to markdown to pdf or png with the support of pandoc and typst . Of course, it took more than two months to learn the programming syntax of typst and compile the document template program.

The original intention of the design of the document template is to meet the document writing requirements of my daily work. It is very self-righteous. The main types of these documents are:

  • Technical solution description
  • Work plan
  • Summary
  • Log

Book publishing and academic papers are not considered for the time being.

Where to get this document template program, see [How to get this template]

Styles supported in the template #

The styles formats supported in the document are:

Color settings in the template #

The document has two versions: dark and light. The document page is divided into two sizes: A4 and 300/650 aspect ratio for mobile reading.

Code highlight color themes are:

  • ayu :
    • ayu-mirage
    • ayu-dark
    • ayu-light
  • Catppuccin
    • Catppuccin Frappe
    • Catppuccin Latte
    • Catppuccin Macchiato
    • Catppuccin Mocha

This template program already contains all the combinations of the above situations.

Demonstrations #

You can directly download userguide.dark.ayu-dark.pdf to see the look and feel.

Emphasis #

The markdown content is as follows:


Emphasis, also known as italics, uses an *asterisk* or _underline_.

Emphasis, also known as bold, uses an **asterisk** or __underline__.

Use a combination of **asterisk and _underline_** for emphasis.

Strikethrough uses two tildes. ~~Strike this out.~~

**This is bold text**

__This is bold text__

*This is italic text*

_This is italic text_

~~Strikethrough~~

Renders to:

Emphasis (bold or italic) example
Emphasis (bold or italic) example


Unordered list #

The markdown content is as follows:


* Unordered lists can be made with an asterisk (`*`)
- or a minus sign (`-`)
+ or a plus sign (`+`)

+ Create a list by starting a line with `+`, `-`, or `*`
+ Create a sublist by indenting 2 spaces:
  - A change in the marker character forces the start of a new list:
    * Ac tristique libero volutpat at
    + Facilisis in pretium nisl aliquet
    - Nulla volutpat aliquam velit
+ Very simple!

+ Unordered lists can also be
+ mixed with numbered lists
  1. Indent and create a numbered list item
  2. Another numbered item
+ Another unordered list item

Renders to:

Unordered list example
Unordered list example


Ordered list #

The markdown content is as follows:


1. First ordered list item
2. Another item
  * Unordered list
1. The actual number doesn't matter, as long as it's a number
  1. The numbers will reorder
4. Another item.
   You can also properly indent paragraphs in list items.
5. Extra blank lines

   In addition to properly indenting paragraphs, adding an extra blank line before a paragraph also forms a new indented paragraph with an indented first line.

   In addition to properly indenting paragraphs, adding an extra blank line before a paragraph also forms a new indented paragraph with an indented first line.
7. One more item

1. Make changes
  1. Fix bugs
  2. Improve formatting
    - Make headings bigger
2. Push my commit to GitHub
3. Open a pull request
  * Describe my changes
  * Mention all members of my team
    * Ask for feedback

Renders to:

Ordered list example
Ordered list example


Task list #

The markdown content is as follows:

- [x] Finish my changes
- [ ] Push my commits to GitHub
- [ ] Open a pull request
- [x] Support \@mentions, #refs, [links](), **formatting**, and <del>tags</del>
- [x] Require list syntax (supports any unordered or ordered list)
- [ ] This is a complete project
- [ ] This is an incomplete project
- ✅ This line is not a task list item, but it is also a list item

Rendered as:

Task list example
Task list example


emoji #

markdown The content is as follows:


*emoji marks*: 😄 😡 😓 👇

*emoji symbols*: 😀😃😄😁🐶🐱🐭🐹
🍏🍐🍉🍇🍓
⚽️🏐🏈🏀
🚗🚕🚙🚌
⌚️📱📲💻⌨️
🩷❤️🧡💛🉐㊙️㊗️🈴🉑☢️☣️
🏳️🏴🏴‍☠️🏁
⚠️🌟🔥👍✅

Renders to:

Example of emoji
Example of emoji


The content of markdown is as follows:


[I am an inline-style link](https://www.google.com)

[I am an inline-style link with a title](https://www.google.com "Google's Homepage")

[I am a reference-style link][Any case-insensitive reference text]

[I am a relative reference to a repository file](../blob/master/LICENSE)

[You can use a number for a reference-style link definition][1]

Or leave it blank and use [the link text itself].

URLs and URLs in angle brackets are automatically converted to links. http://www.example.com or <http://www.example.com>, and sometimes example.com (but not on Github).

Some text indicating that the reference link can follow later.

[Any case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[The link text itself]: http://www.reddit.com

Renders to:

Example of link
Example of link

Picture #

The content of markdown is as follows:


This is the logo:

Inline style:
![Alternative text](./images/icon48.png "Logo Title Text 1")

Quote style:
![Alternative text][Logo]

[Logo]: ./images/icon48.png "Logo Title Text 2"

No caption below the image, and the image is right next to the text:
![Minion](./images/minion.png){width=20%}
![Stormtroopocat](./images/stormtroopocat.png "The Stormtroopocat"){width=20%}

You can also add a caption below the image, which needs to be a separate paragraph, that is, a blank line before and after:

![Image title, some explanation][id]

Define the image location in the quote later in the document:

[id]: ./images/dojocat.jpg "The Dojocat"

You can also specify the image size: 

![Minion](./images/minion.png){width=5%} ![Minion](./images/minion.png){width=10%} 
![Minion](./images/minion.png){width=20%}![Minion](./images/minion.png){width=30%}

Renders to:

Example of picture
Example of picture

Footnote #

markdown The content is as follows:


Footnote 1 link [^1].

Footnote 2 link [^2].

~Inline footnote ^[text of inline footnote] definition.

Repeated footnote reference [^2].

[^1]: Footnotes **can have tags** and multiple paragraphs.

[^2]: Footnote text.

Renders to:

Footnote example
Footnote example


Definition list #

The content of markdown is as follows:


Term
: The term name is on a separate line, and the second line starts with a colon (`: `), followed by a description of the term definition

Another term
: It starts with a colon (`: `), followed by a description of the term definition. *Definition lists* are often used in documents to unify the definitions of professional terms, business terms, and nouns.

Term entry line break
: It is related to the line break interpretation of markdown. If it is `hard_linkbreak`, a line needs to be left blank between entries.
This is not a definition term
: The definition term is not separated from the previous entry by a blank line and cannot become a new entry.

Term definition paragraph
: The term content is indented to the right as a whole paragraph.

Renders to:

Definition list example
Definition list example


Mathematical Equations #

The content of markdown is as follows:


Display on a single line
: $$
e=mc^2
$$

Inline
: This is a bunny, followed by a formula, $e=mc^2$. There can be text after it.

Renders to:

Data formula example
Data formula example


Code highlighting #

markdown The content is as follows:


```
Inline `code` has `backticks` around it.
```

Inline `code` has `backticks` around it.

Code blocks use a pair of triple backticks ```

css sample:

````
```css
@font-face {
  font-family: Chunkfive; src: url('Chunkfive.otf');
}

body, .usertext {
  color: #F0F0F0; background: #600;
  font-family: Chunkfive, sans;
}

@import url(print.css);
@media print {
  a[href^=http]::after {
    content: attr(href)
  }
}
```
````

css highlighting effect:

```css
@font-face {
  font-family: Chunkfive; src: url('Chunkfive.otf');
}

body, .usertext {
  color: #F0F0F0; background: #600;
  font-family: Chunkfive, sans;
}

@import url(print.css);
@media print {
  a[href^=http]::after {
    content: attr(href)
  }
}
``` 

----

javascript sample:

````
```javascript
function $initHighlight(block, cls) {
  try {
    if (cls.search(/\bno\-highlight\b/) != -1)
      return process(block, true, 0x0F) +
             ` class="${cls}"`;
  } catch (e) {
    /* handle exception */
  }
  for (var i = 0 / 2; i < classes.length; i++) {
    if (checkCondition(classes[i]) === undefined)
      console.log('undefined');
  }
}

export  $initHighlight;
```
````

javascript highlighting effect:

```javascript
function $initHighlight(block, cls) {
  try {
    if (cls.search(/\bno\-highlight\b/) != -1)
      return process(block, true, 0x0F) +
             ` class="${cls}"`;
  } catch (e) {
    /* handle exception */
  }
  for (var i = 0 / 2; i < classes.length; i++) {
    if (checkCondition(classes[i]) === undefined)
      console.log('undefined');
  }
}

export  $initHighlight;
```

Renders to:

Code highlight example
Code highlight example

Code highlight example
Code highlight example


Table #

The markdown content is as follows:


*Colons* can be used to align columns.

| Table         | is very       | Cool  |
| ------------- |:-------------:| -----:|
| Column 3 is   | Right-aligned | $1600 |
| Column 2 is   | Centered      | $12   |
| Zebra Stripes | Neat          | $1   |

There must be at least 3 dashes (`-`) between each header cell.

The outer pipes (`|`) are optional and you don't need them to make the raw Markdown line up nicely. You can also use inline Markdown.

Table example, outer pipe characters (|) can be omitted:

Markdown | Less | Pretty
--- | --- | ---
*Still* | `Renders` | **Very well**
1 | 2 | 3

| First heading | Second heading |
| ------------- | -------------  |
| Content cell  | Content cell   |
| Content cell  | Content cell   |

Table example, cell content can be marked up:

| Command | Description |
| --- | --- |
| git status | List all new or modified files |
| git diff | Show differences in files that have not yet been staged |

| Command | Description |
| --- | --- |
| `git status` | List all *new or modified* files |
| `git diff` | Show differences in files that have not yet been staged |

Table example, columns can be freely aligned:

| Left alignment | Center alignment | Right alignment |
| :---           | :---:            | ---:            |
| git status     | git status       | git status      |
| git diff       | git diff         | git diff        |

Table example, special symbols in cells:

| Name     | Character |
| ---      | ---       |
| Backtick | `         |
| Pipe     | \|        |

Renders to:

Table example
Table example

Table example
Table example


Table width and column width #

The pandoc markdown parser supports table formats with two grids that can control the table width and column width, multiline tables and grid tables. The default line width of 72 scii characters can fill the entire page width.

Take grid_stables as an example:


: 2 columns 72 characters

+-----------------------------------+----------------------------------+
| Fruit           Price             | Advantages                       |
+===================================+:=================================+
| Oranges         $2.10             | - cures scurvy                   |
|                                   | - tasty                          |
+-----------------------------------+----------------------------------+

: 3 columns 72 characters

+---------------+-------------------+----------------------------------+
| Fruit         | Price             | Advantages                       |
+===============+===================+:=================================+
| Oranges       | $2.10             | - cures scurvy                   |
|               |                   | - tasty                          |
+---------------+-------------------+----------------------------------+

: 2 columns 37 characters

+---------------+-------------------+
| Fruit         | Price             |
+===============+===================+
| Oranges       | $2.10             |
|               |                   |
+---------------+-------------------+

Renders to:

grid table width example
grid table width example


Take multiline_tables as an example:


: 4 columns 72 characters

------------------------ 
 Centered  Default           Right Left
  Header   Aligned         Aligned Aligned
---------- ------- --------------- -------------------------------------
   First   row                12.0 Example of a row that
                                   spans multiple lines.
------------------------ 


: 3 columns 34 characters

------------------------ 
 Centered  Default           Right
  Header   Aligned         Aligned
---------- ------- ---------------
   First   row                12.0
                                  
------------------------ 


: 2 columns 72 characters

------------------------ 
Centered   Default     Right        Left
Header    Aligned   Aligned         Aligned
-----------------------------       ------------------------------------
   First    row          12.0       Example of a row that
                                    spans multiple lines.
------------------------ 

Renders to:

multiline table width example
multiline table width example


Block Quotes #

The markdown content is as follows:


> Blockquotes are really handy in emails to simulate reply text.
This line is part of the same quote.

Quote separator.

> This is a really long line that will still quote correctly when it wraps. Oh, let's keep writing it to make sure it's long enough to actually wrap for each person. Oh, and you can *put* **Markdown** into a blockquote.

> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between the arrows.

Renders to:

blockquotes example
blockquotes example


gfm alerts #

alerts is a special html css style in GitHub-Flavored markdown. This template has been processed for compatibility. In addition to the note, tip, important, caution, and warning specified by gfm itself, it also supports idea, error, success, goal, and notification. Both uppercase and lowercase are acceptable.

The markdown content is as follows:


> [!NOTE]
> This is a note

> [!TIP]
> This is a tip

> [!IMPORTANT]
> This is important

> [!CAUTION]
> Be careful with the problem described here

> [!WARNING]
> Warning
>


>[!Idea]
> This is an idea
>
>

> [!Error]
> This is an error
>

> [!Success]
> When successful

> [!Goal]
> This is the goal
>

> [!Notification]
> There is a notification here
>

Renders to:

gfm alerts example
gfm alerts example


horizontal rule #

The markdown content is as follows:


Three symbols or more

Three hyphens `---`

---

Three asterisks `***`

***

Three underscores `___`

___

Renders to:

horizontal rule example
horizontal rule example


title #

The markdown content is as follows:


Alt-H2
------
# (only for demonstration) h1 title
## h2 title
### h3 title
#### h4 title
##### h5 title
###### h6 title

Or, for H1 and H2, use the underline style:

(only for demonstration) Alt-H1
======

Alt-H2
------

Renders to:

section title example
section title example


Usage #

Install this template as a typst local package, that is, copy or link it to the user’s local directory {data_dir}/typst/packages/local, so that when using pandoc to convert markdown to pdf, specify the --template parameter as a template in the template folder themekit/{version number}/pandoc/.

  • {data_dir} is related to the operating system

For detailed operations, see the [User Guide] of the template program

How to get this template #

If the above demonstration meets your daily use requirements, or if you need to develop and maintain such a program yourself but don’t want to start from scratch, you can refer to this template.

This pandoc typst template program for converting markdown to pdf, has no plans to be open source yet. You can get the authorized version from the following link.


chinese version of this article: 《使用 pandoc 和 typst 将 markdown 转换为 pdf》