VSCodeとMarkdownでLaTeX数式を含んだPDF資料をラクに作成するための設定


# 目的
数式を含んだPDF資料をできるだけラクに作成するための環境をラクに構築します。
数式を含んだ資料を作成する手段としては王道のLaTeX組版がありますが、これはお世辞にもラクとは言えません。そこで、このQiita記事を作成する際にも使われているような「Markdown記法にLaTeX数式を埋め込む」スタイルでの資料作成を目指します。

モチベーションとしては以下の方に近いです。私の場合は大学の演習や輪読の授業で資料を作る必要性に迫られています。

https://qiita.com/flanny7/items/c0f3772f71ede8ed7251

しかし、上の記事内で紹介されている『Markdown Preview Enhanced』はプレビュー機能に特化しており、PDF出力では『Markdown PDF』に軍配が上がります。また、上の記事内では数式表示には触れられていません。本記事ではこれらの問題を解決します。

# 環境要件
- VSCodeがインストールできる/されていること。
- ショートカットキーの表示がMacになっておりますので、WindowsやLinuxの方は適宜読み替えてください。（例：`Command` -> `Ctrl`）

# 結論
VSCodeを用いてMarkdown記法によって資料を作成し、VSCodeの拡張機能である『Markdown PDF』を用いてプレビュー・PDF出力を行います。ここで、数式の表示にはQiitaの数式表示にも使用されているMathJaxを使用します。

## 手順1
VSCodeの拡張機能『Markdown PDF』をインストールします。
![スクリーンショット 2023-04-08 2.05.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684531/5c8c3c67-dddb-34c5-9881-d9cfb3638ddd.png)
ついでに拡張機能『markdownlint』をインストールしておくと、エディタ上でMarkdown記法の構文やスタイルを校正してもらえるのでオススメです。

## 手順2
VSCode上で `Command` + `Shift` + `P` を押す（または、`F1`キーを押す、または、画面上部の検索スペースに`>`を入力する）ことでコマンドパレットを開き、`Preferences: Open User Settings`を選択します。Settings内の検索で「breaks」を検索し、
- `Markdown> Preview: Breaks`
- `Markdown-pdf: Breaks`

の項目にチェックを入れます。

## 手順3
再びコマンドパレットを開き、`Extensions: Open Extensions Folder`を選択します。通常は`~/.vscodes/extensions`というフォルダが開きます。`yzane.markdown-pdf-1.x.x`という名前のフォルダへ移動し、`template`フォルダ内にある`template.html`の内容を以下のように書き換えます。

```html:template.html
<!DOCTYPE html>
<html>
<head>
<title>{{{title}}}</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
{{{style}}}
{{{mermaid}}}
</head>
<!--ここから追記 1.(数式に対応させる)-->
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
      tex2jax:{inlineMath: [['$', '$']]},
      messageStyle: "none"
    });
</script>
<!--追記 1.ここまで-->
<body>
  <script>
    mermaid.initialize({
      startOnLoad: true,
      theme: document.body.classList.contains('vscode-dark') || document.body.classList.contains('vscode-high-contrast')
          ? 'dark'
          : 'default'
    });
  </script>
  <!--ここから追記 2.(--- で改ページ)-->
  <style>  
    hr {  
      opacity: 0;  
      break-after: page;  
    }  
  </style>  
  <!--追記 2.ここまで-->
{{{content}}}
</body>
</html>
```

<details><summary>デフォルトとの差分(diff)</summary><div>

デフォルトの`template.html`と比較した差分は以下です。

```diff_html:template.html
<!DOCTYPE html>
<html>
<head>
<title>{{{title}}}</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
{{{style}}}
{{{mermaid}}}
</head>
+ <!--ここから追記 1.(数式に対応させる)-->
+ <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-+ + + MML_HTMLorMML"></script>
+ <script type="text/x-mathjax-config">
+     MathJax.Hub.Config({
+       tex2jax:{inlineMath: [['$', '$']]},
+       messageStyle: "none"
+     });
+ </script>
+ <!--追記 1.ここまで-->
<body>
  <script>
    mermaid.initialize({
      startOnLoad: true,
      theme: document.body.classList.contains('vscode-dark') || document.body.classList.contains('vscode-high-contrast')
          ? 'dark'
          : 'default'
    });
  </script>
+   <!--ここから追記 2.(--- で改ページ)-->
+   <style>  
+     hr {  
+       opacity: 0;  
+       break-after: page;  
+     }  
+   </style>  
+   <!--追記 2.ここまで-->
{{{content}}}
</body>
</html>
```
</div></details>

設定は以上です。

## 使い方
VSCode上でMarkdownファイル(`.md`)を編集します。この時、エディタ画面の右上に表示されている虫メガネのマークをクリックすると画面が分割されてリアルタイムにプレビューを確認できます。
![スクリーンショット 2023-04-10 17.45.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684531/09fbc38c-7296-5e84-0e46-3246b13ba495.png)
PDFとして出力する際は、エディタ上で右クリック -> `Markdown PDF: Export (pdf)`を選択します。

MathJax環境でLaTeXを書く際には以下のサイトがとても参考になります。表現したい数式ごとにコピペできるテンプレートが揃っていてとても重宝しています。

https://easy-copy-mathjax.nakaken88.com/

#### 見た目のデザインの設定方法

上下左右の余白が狭い (デフォルトでは 1cm) と感じる場合は、以下の手順で設定できます。
VSCode上で `Preferences: Open User Settings`を選択します。Settings内の検索で「margin」を検索し、

- `Markdown> Margin: Bottom`
- `Markdown> Margin: Left`
- `Markdown> Margin: Right`
- `Markdown> Margin: Top`

をそれぞれ編集することで、余白の調整が可能です。

また、Markdown PDFでは一度マークダウン形式のファイルをHTMLに変換してからPDFとして出力しています。したがって、CSS等で組版に当たるものを書くことで、簡単に見た目をリッチにしたり、組版を管理できたりします。
Settings内の検索で「markdown styles」などと検索し、

- `Markdown: Styles`
- `Markdown-pdf: Styles`

の項目で使用したいCSS組版を指定すれば反映されます。またVS Codeのワークスペース機能を使えばプロジェクトごとに異なる組版を設定することができるため管理が楽です。

参考

https://h-s-hige.hateblo.jp/entry/20190405/1554467885

https://qiita.com/tkms0106/items/37c17c1a559611266d03

https://qiita.com/reona396/items/8ad9a4ca59f10257e073

# 解説

## なぜ手順2が必要か？
通常のMarkdown記法では、`Enter`キーを押しても文章は改行されず、半角スペースを2つ並べることで初めて改行タグ \<br> が挿入されます。Settings内で`Markdown> Preview: Breaks`と`Markdown-pdf: Breaks`の項目にチェックを入れることで、`Enter`キーで通常の改行が打てるようになります。

## なぜMathJaxか？（`template.html`内の追記1.について）
Markdown PreviewではKaTeXが使用されていますが、これではalign環境をはじめとしたいくつかのLaTeX記法が使用できません。そこで、数式の表示にはQiitaの数式表示にも使用されているMathJaxを使用します。この部分については以下の記事を参考にしています。

https://qiita.com/ossyaritoori/items/5e7b3d40505de6288e3c

## `template.html`内の追記2.について
追記2.の内容によって、Markdown上で`---`と入力するだけで改ページすることができます。これは以下の記事の内容を参考にしています。

https://bitto.jp/page-break/

なお、改行をプレビュー画面で確認することはできません。残念。また、追記2.の内容がなくとも、
```html
<div style="page-break-before:always"></div>
または
<div class="page"/>
```
を用いて改行する事ができます。

# 注意

## 数式中の `\` (バックスラッシュ) がMarkdownのエスケープ処理の対象になる

LaTeXの数式に含まれる `\` がMarkdownのエスケープ処理の対象となる場合があります。
`\sum` や `\left(` `\right)`のようにコマンドを表すバックスラッシュは問題ないのですが、改行`\\` や波カッコ `\{` `\}` のバックスラッシュにはエスケープ処理が走ります。
この問題はQiitaの記事を執筆する際にも確認されており、以下の記事で提起されています。

https://qiita.com/BlueRayi/items/7965798ba1127d269ebb

例えば

```latex
$\varnothing$ は元を持ちませんが, $\{ \varnothing \}$ は空集合という元を持ちます。 
よって $\varnothing$ と $\{ \varnothing \}$ はまったく違う集合です。
```

によって期待される表示は

> $\varnothing$ は元を持ちませんが, $\\{ \varnothing \\}$ は空集合という元を持ちます。 
> よって $\varnothing$ と $\\{ \varnothing \\}$ はまったく違う集合です。

なのですが、Markdown PDF や Qiita では

> $\varnothing$ は元を持ちませんが, $\{ \varnothing \}$ は空集合という元を持ちます。 
> よって $\varnothing$ と $\{ \varnothing \}$ はまったく違う集合です。

と表示されます。これは数式中の `\{` `\}` のバックスラッシュがエスケープ処理の対象となり、

```latex
$\varnothing$ は元を持ちませんが, ${ \varnothing }$ は空集合という元を持ちます。 
よって $\varnothing$ と ${ \varnothing }$ はまったく違う集合です。
```

に置き換えられてしまったためです。

### 強引な解決法

バックスラッシュの前にさらにバックスラッシュを書きます。すなわち `\{` ではなく `\\{` と書くことで、2つ目のバックスラッシュを生き延びさせてTeXのパーザに渡すことができます。しかしこの方法ではVS Code上のプレビュー画面で Katex Error が表示されてしまい、プレビューすることができません。

### ケースごとに解決する方法

波カッコについては、`\{` `\}` の代わりに `\lbrace` `\rbrace` を用いることでバックスラッシュが数式中のコマンドであることが認識され、エスケープ処理の対象から外すことができます。

```latex
$\varnothing$ は元を持ちませんが, $\lbrace \varnothing \rbrace$ は空集合という元を持ちます。 
よって $\varnothing$ と $\lbrace \varnothing \rbrace$ はまったく違う集合です。
```

> $\varnothing$ は元を持ちませんが, $\lbrace \varnothing \rbrace$ は空集合という元を持ちます。 
> よって $\varnothing$ と $\lbrace \varnothing \rbrace$ はまったく違う集合です。

また、改行についても同様に工夫して処理できます。
align, case, pmatrixなどを使用する場合は、改行の際に`\\`ではなく`\cr`またはが使用できます。`\\`を使った場合、プレビューでは狙い通りに表示されるのですが、PDF出力結果が一行にまとめられてしまいます。

```latex:example.md
$$
\begin{align}
a &= b \\
  &= c
\end{align}
$$
```

VSCode上でのプレビュー結果
![スクリーンショット 2023-04-08 2.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684531/b32d1f73-f651-59c7-c832-c730b81c32c2.png)

PDF出力結果
![スクリーンショット 2023-04-08 2.22.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684531/b0f0a981-fa70-b2c5-6b80-c489df722d39.png)

改行に`\cr`を用いると、プレビュー、PDF出力ともに2行で表示されます。

```latex:example.md
$$
\begin{align}
a &= b \cr
  &= c
\end{align}
$$
```

VSCode上でのプレビュー結果
![スクリーンショット 2023-04-08 3.34.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684531/eb73abb1-9e40-644d-2df8-24232cc163bd.png)

PDF出力結果（式番号は出ません）
![スクリーンショット 2023-04-08 2.24.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684531/bd7c2b61-86ef-1b25-96a7-42a75a21926e.png)

この方法では個々のケースごとにLaTeXで他の表現を調べる必要がありますが、プレビューを利用することができます。

## 特定の環境で数式のフォントが不自然になる

2023年5月現在、MacOS Venturaにおいて、MathJaxを用いた数式の表示が崩れる（文字や記号がブロック体で表示される）不具合が報告されています（私も困っています）。以下の方が詳しく解説してくださっています。

https://qiita.com/yoya/items/c54f401a9cb78930f9c8

これを解決するためには、`template.html`に記入した内容のうちMathJaxに関係する「追記1.」の部分を以下のように書き換えれば良いです。

```html:template.html
<!--ここから追記 1.(数式に対応させる)-->
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
      "HTML-CSS": { fonts: ["TeX"] },
      tex2jax:{inlineMath: [['$', '$']]},
      messageStyle: "none"
    });
</script>
<!--追記 1.ここまで-->
```
<details><summary>差分(diff)</summary><div>

```diff_html:template.html
<!--ここから追記 1.(数式に対応させる)-->
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
+     "HTML-CSS": { fonts: ["TeX"] },
      tex2jax:{inlineMath: [['$', '$']]},
      messageStyle: "none"
    });
</script>
<!--追記 1.ここまで-->
```

</div></details>

## 出力したPDFファイルのテキスト選択の挙動がおかしい

Markdown PDFで書き出したPDFをMac標準のプレビュー機能で開くと、見た目には問題ないのですが、テキスト選択の挙動がおかしくなります。具体的には、選択している文章のハイライトが少しずれていたり、選択した文章を他の場所にコピペすると文章が逆さ順になったりします (PDF文書の「あいうえお」を選択して他の場所にコピペすると、「おえういあ」になる)。
私の手元で実験してみると、どうやらこれはChromeやMicrosoft Edgeの「印刷」機能で書き出したPDFファイルのほぼ全てで発生する現象のようです。詳しい原因は不明です。
Mac標準のプレビューではなくChromeでPDFファイルを開くと、問題なくテキスト選択やコピー・ペーストができました。

以上です。ありがとうございました。