複数のMarkdownをもとに体裁の整ったPDFを作る(Pandoc + wkhtmltopdf)

# 目次
 
- [目次](#目次)
- [この記事でできること](#この記事でできること)
- [はじまり、はじまり](#はじまりはじまり)
- [PDF作成のためのレシピ](#pdf作成のためのレシピ)
  - [必要なソフトウェア](#必要なソフトウェア)
  - [前提（ファイル・フォルダ構造の説明）](#前提ファイルフォルダ構造の説明)
- [PDFに向けて個別整備が必要な事項についての説明](#pdfに向けて個別整備が必要な事項についての説明)
  - [CSSのカスタマイズ](#cssのカスタマイズ)
    - [カスタマイズ内容の紹介](#カスタマイズ内容の紹介)
    - [目次および見出しの自動採番定義の追記](#目次および見出しの自動採番定義の追記)
    - [github-markdown-light.css のCSSクラスの微修正](#github-markdown-lightcss-のcssクラスの微修正)
      - [表(tableタグ)幅の固定化](#表tableタグ幅の固定化)
      - [コードブロック(preタグ)の幅の固定化](#コードブロックpreタグの幅の固定化)
      - [コードブロック(preタグ)の内の折り返し強制](#コードブロックpreタグの内の折り返し強制)
      - [全体的な見た目調整（任意：筆者個人の趣味）](#全体的な見た目調整任意筆者個人の趣味)
  - [表紙および目次用Markdownファイルのデザイン](#表紙および目次用markdownファイルのデザイン)
    - [表紙のデザイン](#表紙のデザイン)
      - [・`markdown-body`クラスを適用したdivタグ](#markdown-bodyクラスを適用したdivタグ)
      - [・`style属性`の使用](#style属性の使用)
      - [・改ページ用divタグの記述](#改ページ用divタグの記述)
    - [目次領域のデザイン](#目次領域のデザイン)
- [本文執筆について](#本文執筆について)
- [Markdownファイルの結合](#markdownファイルの結合)
  - [結合したMarkdownファイルに対して目次を追記（Markdown All in Oneを利用）](#結合したmarkdownファイルに対して目次を追記markdown-all-in-oneを利用)
  - [目次を追記したMarkdownファイルをHTMLに変換（pandocを利用）](#目次を追記したmarkdownファイルをhtmlに変換pandocを利用)
  - [デザイン用CSSを適用するクラスを指定したdivの閉じタグを追記](#デザイン用cssを適用するクラスを指定したdivの閉じタグを追記)
  - [HTMLファイルをPDFに変換（wkhtmltopdfを利用）](#htmlファイルをpdfに変換wkhtmltopdfを利用)
  - [謝辞](#謝辞)

# この記事でできること

- 複数のMarkdownファイルを基に表紙や目次の採番がされた1冊のPDFを作成する。
- puppeteer（Headless Chrome）に依存しない方法でPDFを作成する。
- JTCな会社や仕事だけど、WordやExcelはもうこりごりなり、ドキュメントはMarkdownで書きたいんだ、という人向けの、ニッチな記事です。

作成のおおまかな流れと、できあがりのイメージはこんな感じです。

1. Markdownファイルを作る
2. Markdownファイルを`1つに結合`する
3. 1つに結合したMarkdownに`目次を追加`する
4. 目次が追記されたMarkdownを`Pandoc`を使ってHTMLに変換する
5. HTMLを`wkhtmltopdf`を使ってPDFに変換する

![usecase.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267641/d791dfc7-20c4-20d2-f04d-abb9815e4eb5.png)

![sample-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267641/db0d9ff1-1486-da24-7db8-e195c9884c90.png)

# はじまり、はじまり

GitHub上でMarkdownファイルベースでドキュメントを作成していても、いろいろな事情から一冊のPDFにしたいというような場面があるかと思います。え？ない？いやいやまぁまぁ。

で、大体の場合は「[md-to-pdf](https://dev.classmethod.jp/articles/md-to-pdf/)」とかを使えば事足りると思うのですが、

- いわゆるWordで作っていたような体裁が好ましい(という圧力)
- 表紙つけたい
- 章や節に連番つけたい

みたいな ~~面倒な~~ 要求があったり、多くのPDF変換ツールが裏で動かしている puppeteer / Headless Chrome が、(おそらく)PCのセキュリティ規制に引っかかって起動しないというXXXな場合があったりします。これはたぶんレアケースだと思いますが、自分がハマったのでやむなくこの記事みたいな整理を趣味もかねてやってみました。

この記事では、そんな愉快な状況に対して地道に整理した `Markdownファイルからそれなりの見た目のPDFを作成する手順について` 色々試行錯誤した内容を網羅的に書いていこうと思います。ただ、やたら長くなってしまったので読むのがめんどくさい方は、[記事の中身をサンプル実装した物](https://github.com/u-tanick/making-pretty-pdf-from-markdown) を公開しているのでこっちをご利用されるのが手っ取り早いと思います。（この記事はほぼ作業ログのような内容になってしまったので）

# PDF作成のためのレシピ

## 必要なソフトウェア

作成手順や仕様を説明する前に、提示しておいたほうが良い情報として、動作させるのに必要なSWについて記載しておきます。

**PDF変換のために利用（基本的に最新版でいいはず）**

- Python
- Pandoc
- wkhtmltopdf

**Markdownの編集／目次の自動作成に利用**

- VS Code
- VS Codeプラグイン：Markdown All in One
- VS Codeプラグイン：markdownlint
  - これについては本文では細かくは触れませんが、きれいなMarkdown出ないと変換に失敗するので、作法を統一・強制するためにも重要

**HTML/PDFの体裁デザインの元ネタに使用**

- github-markdown-light.css (改変して利用)
  - [入手元はこちらに記載](#謝辞)
  - [本記事の構成のサンプルを公開しているGitHubに、改変済みのものが入っています](https://github.com/u-tanick/making-pretty-pdf-from-markdown)

必要なソフトウェアはそれぞれの公式サイトから入手してください。インストール手順もサイト内に説明があるのでここでは割愛します。英語イヤ！という方は、BingChatやChatGPTに聞いてみるといいかもしれません。

|ソフトウェア|入手元（公式サイト）|
|:--|:--|
|Python|https://www.python.org/downloads/|
|Pandoc|https://pandoc.org/installing.html|
|wkhtmltopdf|https://wkhtmltopdf.org/downloads.html|

※ wkhtmltopdfは、システム環境変数のPathにexeがあるフォルダまでのパスを設定する必要があります。

## 前提（ファイル・フォルダ構造の説明）

これ以降の説明の前提として、ドキュメント作成および今回作成したスクリプトやコマンドを動作させる前提となるファイル・フォルダ構造の定義を説明します。

フォルダ構造および基本的なファイルの配置は下図の構成となります。

![filefolder.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267641/d16c85fa-194f-46b0-4f14-e3e23896ff51.png)

ファイル種別固有の仕様についての補足を記載します。

- Markdownファイルは、章単位で作成されていおり、各見出しレベルは下記のルールに従って記述されていること。
  - 章タイトル： `#`
  - 節タイトル： `## ～ #####`
- Markdownから画像ファイルへの参照は、mdファイルからの相対パスで記述されていること。
  - `![ALT属性](images/画像ファイル名)`

とはいえ、ひとつの章がやたら大きくなってしまった場合は適切にファイルを分けて記述していくこともあるかと思います。
この辺は実際に目次構成を検討してどのくらいのMarkdownファイルに分けるのかを決めてから取り掛かるのが良いと思います。

> ※ 章単位という指定にしたのは、後述するMarkdownファイルを結合するスクリプトを作った際に、Markdownファイル単位で改ページが挿入されるようにしたからです。

# PDFに向けて個別整備が必要な事項についての説明

PDFの見栄えをデザインするにあたって、ドキュメント本文の作成とは別に整備しておく次の事項について、説明します。

- [CSSのカスタマイズ](#cssのカスタマイズ)
- [表紙および目次用Markdownファイルのデザイン](#表紙および目次用markdownファイルのデザイン)

## CSSのカスタマイズ

今回のPDF作成では、多くの人が見慣れていると思われるGitHub上で表示されるMarkdownのデザインに似せるため、[GitHubのMakdownプレビューで適用されているCSS（GitHubで公開されている）](https://github.com/sindresorhus/github-markdown-css)を利用します。今回の目的はPDFファイルの作成なので、白基調のデザインとなる `github-markdown-light.css` を利用します。

> ※ このリポジトリは `MIT Licence` と規定されているので、規定の範囲内において使用可能とみなして使和せていただきました。かんしゃあ。

入手したファイルは、[前提（ファイル・フォルダ構造）の説明](#前提ファイル・フォルダ構造の説明) に記載にしたがって、`_HTML` フォルダの中に入れます。

[この記事のサンプルを公開しているGitHub](https://github.com/u-tanick/making-pretty-pdf-from-markdown) では後続で説明するカスタマイズ済みのCSSファイル名を、`github-markdown-light-custom4pdf.css` としています。

### カスタマイズ内容の紹介

元ファイルとなる `github-markdown-light.css` はHTMLに適用してブラウザで見る分にはいいのですが、PDFにした場合は紙面の幅に対して表やコードブロックの記述がはみ出してしまうなどの問題があるため、調整が必要です。

本記事では `github-markdown-light.css` に対して次のような修正を実施します。

- [目次および見出しの自動採番定義の追記](#目次および見出しの自動採番定義の追記)
- [github-markdown-light.css のCSSクラスの微修正](#github-markdown-lightcss-のcssクラスの微修正)
  - [表(tableタグ)幅の固定化（必須）](#表tableタグ幅の固定化)
  - [コードブロック(preタグ)の幅の固定化](#コードブロックpreタグの幅の固定化)
  - [コードブロック(preタグ)の内の折り返し強制](#コードブロックpreタグの内の折り返し強制)
  - [全体的な見た目調整（任意：筆者個人の趣味）](#全体的な見た目調整任意筆者個人の趣味)

以下に、各修正内容の詳細を説明します。

### 目次および見出しの自動採番定義の追記

HTML化やPDF化した際の目次や見出しに対して自動的に採番する設定をCSSで実装することができます。
ここでは、記述するコードのみ示すこととし、仕組みの詳細は [参考元となる @UKawamura さんの記事](https://qiita.com/UKawamura/items/42f907c88686fb3be4da) をご覧ください。

`github-markdown-css-light.css` の末尾に、見出しの自動採番用コードと目次の自動採番用コードの内容を追記します。

**見出しの自動採番用コード**

``` css
body{
  counter-reset: chapter;
}

h1{
  counter-reset: sub-chapter;
}

h2{
  counter-reset: section;
}

h3{
  counter-reset: sub-section;
}

h4{
  counter-reset: sub-sub-section;
}

h5{
  counter-reset: sub-sub-sub-section;
}

h1::before{
  counter-increment: chapter;
  content: counter(chapter) ". ";
}

h2::before{
  counter-increment: sub-chapter;
  content: counter(chapter) "." counter(sub-chapter) ". ";
}

h3::before{
  counter-increment: section;
  content: counter(chapter) "." counter(sub-chapter) "." counter(section) ". ";
}

h4::before{
  counter-increment: sub-section;
  content: counter(chapter) "." counter(sub-chapter) "." counter(section) "." counter(sub-section) ".";
}

h5::before{
  counter-increment: sub-sub-section;
  content: counter(chapter) "." counter(sub-chapter) "." counter(section) "." counter(sub-section) "." counter(sub-sub-section) ".";
}

h6::before{
  counter-increment: sub-sub-sub-section;
  content: counter(chapter) "." counter(sub-chapter) "." counter(section) "." counter(sub-section) "." counter(sub-sub-section) "." counter(sub-sub-sub-section) ".";
}
```

**目次の自動採番用コード**

``` css
div.ToC ul {
  counter-reset: section;
}

div.ToC li {
  list-style: none;
}

div.ToC ul>li:before {
  counter-increment: section;
  content: counters(section, '.') '. ';
}
```

### github-markdown-light.css のCSSクラスの微修正

PDFは印刷紙面を想定したフォーマットとなるため、それを意識したCSSに修正する必要があります。

本記事で修正後としている数値については、利用に際して問題がなさそうな値で書いているだけなので、各人の趣味に合わせての調整は自由です。追加・削除しているものは踏襲されるほうが安全かと思います。

また、説明に記載している `〇〇行目付近` という記述は、オリジナルの `github-markdown-light.css` の行数を示しています。

#### 表(tableタグ)幅の固定化

このカスタマイズでは、表はPDFの紙面幅に合わせて固定化させています。

`github-markdown-css-light.css` の193行目付近の `.markdown-body table` クラスに対して、`width` を固定値に修正、`table-layout` を追加し、`display` および `max-width` を削除します。

修正前

``` css
.markdown-body table {
  border-spacing: 0;
  border-collapse: collapse;
  display: block;
  width: max-content;
  max-width: 100%;
  overflow: auto;
}
```

修正後

``` css
.markdown-body table {
  border-spacing: 0;
  border-collapse: collapse;
  width: 825px;
  overflow: auto;
  table-layout: auto;
}
```

#### コードブロック(preタグ)の幅の固定化

表と同様に、コードブロックについてもPDFの紙面幅に合わせることにします。

`github-markdown-css-light.css` の345行目付近の `.markdown-body pre` クラスに対して、`width` を追加します。ここでは、`border` も追加されていますが、こちらは筆者の趣味です。

修正前

``` css
.markdown-body pre {
  margin-top: 0;
  margin-bottom: 0;
  font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
  font-size: 12px;
  word-wrap: normal;
}
```

修正後

``` css
.markdown-body pre {
  margin-top: 0;
  margin-bottom: 0;
  font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
  font-size: 12px;
  word-wrap: normal;
  width: 795px;
  border: 1px solid #cccccc;
}
```

#### コードブロック(preタグ)の内の折り返し強制

HTMLでは、画面幅が柔軟に変えられたり、横スクロールができますが、PDFは紙面幅が固定なためデフォルトのCSSでは一行が長いコードは、紙面幅をオーバーして表示されてしまう、という問題があります。
この問題に対処するため、固定化したコードブロックの幅に合わせて中のテキストが強制的に折り返されるように修正します。

`github-markdown-css-light.css` の710行目付近の `.markdown-body pre` クラスに対して、`white-space` 属性の値を `pre-wrap !important` に修正します。

修正前

``` css
.markdown-body pre>code {
  padding: 0;
  margin: 0;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0;
}
```

修正後

``` css
.markdown-body pre>code {
  padding: 0;
  margin: 0;
  word-break: normal;
  white-space: pre-wrap !important;
  background: transparent;
  border: 0;
}
```

#### 全体的な見た目調整（任意：筆者個人の趣味）

[GitHubで公開しているサンプル](https://github.com/u-tanick/making-pretty-pdf-from-markdown) に含まれるカスタマイズ済みのCSSには、筆者の個人の趣味により下記に示す微調整内容も併せて適用しています。この辺りは、完璧の趣味の世界なので、各自ご自由に修正いただいてかまいません。

**・ドキュメント全体の文字サイズを少し小さくした**  
1行目付近の `.markdown-body` クラスに対して `font-size` を `16px` から `14px` に変更してあります。

**・箇条書きの行間を微調整した**  
525行目付近の `.markdown-body ul ul, ～ ol ul` クラスに対しては、`margin-top` および `margin-bottom` の値を `0px` から `7px` に変更してあります。
同様に、537行目付近の `.markdown-body li+li` クラスの `margin-top` の値を `.25em` から `.75em` に変更してあります。

**・注釈の章の付近にドキュメントとしては余計な罫線が表示されていた**  
227行目付近の `.markdown-body hr` クラスに対して `margin` を全て `0` に、`background-color` を `#ffffff` に変更してあります。
また、894行目付近の `.markdown-body .footnotes` クラスに対して `color` を `#000000` に、`border-top` を `0px solid #ffffff` に変更してあります。

**・ユーザーエージェントリセット用CSSの適用**  
CSSのカスタマイズをする際、ブラウザの開発ツール（F12）を使用して適用されたCSSを解析しますが、ブラウザ固有のデフォルト値となる `User Agent Stylesheet` を無効化することで、より意図したとおりの修正が行いやすくなります。
そのため、 [こちらで公開されているコード](http://html5doctor.com/html-5-reset-stylesheet/) を、CSSファイルの冒頭に追記します（本記事でのコードプレビューは省略します）。

## 表紙および目次用Markdownファイルのデザイン

### 表紙のデザイン

表紙や目次を記載するためのファイルは、Markdownファイルとして作成しますが、紙面としてのレイアウトデザインは、HTMLタグを活用して記述します。

**HTMLタグを使った表紙デザインをする際の注意事項**

表紙レイアウトのためのHTMLタグは可読性のためにインデントを付けたくなりますが、それをすると **PandocによるHTML変換時にpreタグ内の要素だと判断されてしまい、style属性が効かなくなってしまう** ため左詰めで記述します。

ここではよくある社内文章的な表紙レイアウトを想定したHTMLの記述例を示します。見た目HTMLですが、.mdファイルとして作成します。

``` html
<div class="markdown-body">
<div style="text-align: center;">
<div style="font-size: 50px; line-height: 120%; padding: 300px 0;">
ドキュメントタイトル
</div>
<div style="font-size: 40px; line-height: 120%; margin: 100px auto;">
サブタイトル
</div>
<div style="font-size: 20px; line-height: 150%; margin: 100px auto;">
作成日時<br>
作成者
</div>
</div>
<div style="page-break-before: always;"></div>
```

この記述例において特徴となるポイントを次に説明します。

#### ・`markdown-body`クラスを適用したdivタグ

1行目にあるdivタグおよび`markdown-body`クラスは、先に説明した `github-markdown-css-light.css` をドキュメント全体に対して適用させるための必須要素です。
表紙がない場合でも`本文全体の中で1行目に必ず記述`する必要があります。

また、表紙ファイルの中では閉じタグを記述しません。このクラスの閉じタグは、Markdownから変換されたHTMLファイルの末尾のBodyタグの直上に記述する必要があります。
HTMLファイルに対して、divの閉じタグを記述する方法については、後述の [デザイン用cssを適用するクラスを指定したdivの閉じタグを追記](#デザイン用cssを適用するクラスを指定したdivの閉じタグを追記) で説明します。

#### ・`style属性`の使用

レイアウトの調整用に別途CSSクラスを用意してもよいですが、mdファイル単体に対してCSSファイルで定義したクラスを適用しても、VS CodeのMarkdownのプレビュー上では外部のクラス定義は適用されないのでここではstyle属性でべた書きしています。これでVS Codeのプレビュー画面でもレイアウトの確認ができるようになります。

#### ・改ページ用divタグの記述

表紙の末尾の位置に `改ページ用divタグ` を記述しています。このタグは、本文のMarkdownファイルでも任意の個所に記述することでPDFファイル上での改ページを適用することができます。
ドキュメント内での部や章といった大きな区切りのタイミングで記述されることが多いと思います。

``` html
<div style="page-break-before: always;"></div>
```

### 目次領域のデザイン

個別に作成されたMarkdown単体で目次を作ってもドキュメント全体としての目次にはならないため、ドキュメントの目次はMarkdownファイルを結合したあとで、VS Codeプラグイン `Markdown All in One` の目次生成機能を利用して生成します。

表紙ファイルには、この目次生成機能を実施する場所を示すHTMLタグを、表紙領域に続けて記述します。

下記に、目次用のHTMLの記述例を示します。

``` html
　　：
表紙領域のデザイン（先に説明済み）
　　：
<span style="font-size: 25px;">目次</span>
<div class="ToC">

★Markdownファイルを結合したのち、この場所にVS Codeプラグイン `Markdown All in One` の目次生成機能を利用してドキュメント全体に対する目次を作成する。

</div>
<div style="page-break-before: always;"></div>
```

この記述例において特徴となるポイントを次に説明します。

**`ToC`クラスを提供したdivタグ**

`ToC`クラスは、[目次および見出しの自動採番の追記](#目次および見出しの自動採番定義の追記) で説明したCSSを適用するクラスです。このクラスが書かれたdivタグの中にVS Codeの機能で目次を生成することで、HTMLおよびPDF化した際の目次に対して自動採番が適用されます。

# 本文執筆について

本文の執筆は、従来通りMarkdownファイルを作成すればよいので割愛します。
この後に説明するMarkdownファイルの結合スクリプトの仕様に従って、画像ファイルは`images`フォルダに格納することとします。

# Markdownファイルの結合

[前提（ファイル・フォルダ構造の説明）](#前提ファイル・フォルダ構造の説明) の記載にしたがって、`_MD` フォルダにドキュメントとして作成したMarkdownファイルを結合して格納します。
また、それに合わせて、画像ファイルも、`_MD` フォルダの中に`images`フォルダを作成し集約します。

以上の仕様は、手動でも実行可能ですが、さすがに面倒なのでPythonスクリプトの例を記載します。
このスクリプトは [サンプル公開GitHub](https://github.com/u-tanick/making-pretty-pdf-from-markdown) でも同様のものを公開しています。

> 正直Pythonビギナーなんで上手くない書き方のところも多々あるかもですが、ご容赦！

``` py
import os
import glob
import shutil
import yaml
import io, sys

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='UTF-8')
sys.stderr = io.TextIOWrapper(sys.stdout.buffer, encoding='UTF-8')

# _MDフォルダの中にimagesというフォルダを作成する、既に存在している場合削除し作り直す。
MD_DIR = "_MD\\"
IMAGES_DIR = "images"
DEST_IMAGES_DIR = MD_DIR + IMAGES_DIR
if os.path.exists(DEST_IMAGES_DIR):
    shutil.rmtree(DEST_IMAGES_DIR)
os.mkdir(DEST_IMAGES_DIR)

CURRENT_DIR = os.getcwd()

# imagesフォルダのパスを再帰的に取得し、フォルダの中身を_MD/imagesフォルダにコピー
for folder in glob.glob("**/images", recursive=True):
    if (folder == DEST_IMAGES_DIR):
        continue
    list_file_name = os.listdir(folder)
    for i_file_name in list_file_name:
        join_name = os.path.join(CURRENT_DIR, folder, i_file_name)
        DEST_IMAGES_PATH = os.path.join(CURRENT_DIR, DEST_IMAGES_DIR)
        if os.path.isfile(join_name):
            shutil.copy(join_name, DEST_IMAGES_PATH)
        else:
            shutil.copytree(join_name, os.path.join(DEST_IMAGES_PATH, i_file_name))

# yamlファイルを読み込み、Markdownファイルの結合に必要な情報を取得
CONFIG_YAML = "mppdfmd-config.yaml"
with open(CONFIG_YAML, encoding="utf-8") as f:
    filenames = yaml.load(f, Loader=yaml.FullLoader)
md_files = filenames["md-files"]
merged_file_name = MD_DIR + filenames["merged-file-name"]

# Markdownファイルの中身を順に結合する、その際ファイル間には改ページタグを挿入する
with open(merged_file_name, "w", encoding="utf-8") as merged_file:
    for mdfile in md_files:
        with open(mdfile, encoding="utf-8") as read_file:
            merged_file.write(read_file.read())
            if mdfile != md_files[-1]:
                merged_file.write("\n\n")
                merged_file.write("<div style=\"page-break-before: always;\"></div>")
                merged_file.write("\n\n")
```

あまり特別なことはしていませんが、個別に作成されたMarkdownファイル毎に、改ページを差し込むようにしてみました。
また、結合するファイルの順序や、結合後のファイル名などを、yamlの設定ファイル（下記）から読み込むようにしています。

``` yaml
# 結合結果となるMarkdownファイル名（拡張子含む）
merged-file-name: "sample.md"

# 結合するMarkdownのリスト。margeMD.pyスクリプトから相対パスで記述（拡張子含む）
md-files:
  - CoverAndToC.md
  - foo/chapter1.md
  - bar/chapter2.md
  - bar/bal/chapter3.md
  - Remark.md
```

## 結合したMarkdownファイルに対して目次を追記（Markdown All in Oneを利用）

`_MD` フォルダに結合されたMarkdownと画像ファイルが格納されたため、このMarkdownファイルに対して、[目次および見出しの自動採番の追記](#目次および見出しの自動採番定義の追記) での説明に従ってドキュメント全体の目次を生成します。

**再掲：目次記述用のHTML箇所**

``` html
<div class="ToC">

★Markdownファイルを結合したのち、この場所にVS Codeプラグイン `Markdown All in One` の目次生成機能を利用してドキュメント全体に対する目次を作成する。

</div>
```

- ★の指示に従って、MarkdownファイルをVS Codeで開きます。
- 次に、★の行を削除し、そこにカーソルを置いた状態で `F1` キーを押してコマンドパレットを開き、 `Markdown All in One: 目次（TOC）の作成` を実行します。

![mdallinone_f1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267641/e67727ba-c07a-b310-7b55-3298feef269b.png)

``` html
<div class="ToC">

- [はじめに](#はじめに)
- [ほげほげ](#ほげほげ)
  - [もげもげ](#もげもげ)
    - [まげまげ](#まげまげ)
- [はげはげ](#はげはげ)
  - [ひげひげ](#ひげひげ)
- [おわりに](#おわりに)
- [注釈](#注釈)

</div>
```

**目次生成時の注意点** 

生成した目次と上下にある `<div>` タグの間には `1行以上の空行` を入れておく必要があります。これは続けて実施するPandocによるHTML変換時にMarkdown記法を正しく解釈させるための作法です。目次作成の際には十分ご注意ください。

## 目次を追記したMarkdownファイルをHTMLに変換（pandocを利用）

ここまでで、`_MD` フォルダに表紙と本文が結合され、改ページやCSS適用のためのタグ記述などが適切に設定され、目次のコードも作成された状態のMarkdownファイルが作成された状態になりました。

このMarkdownファイルに対して、`pandoc` を利用することで、先に用意した体裁デザイン用のCSS `github-markdown-css-light.css`  が適用されたHTMLファイルに変換することができます。

また、この結果として生成されるHTMLファイルをブラウザで開くことで、目次や見出しが自動採番されていることも確認できます。

ここでは、[サンプル公開GitHub](https://github.com/u-tanick/making-pretty-pdf-from-markdown) 
に合わせて、結合されたMarkdownファイル名を `sample.md` 、それを変換したHTMLファイル名を `sample.html` 、適用するcssファイルの名称を `github-markdown-light-custom4pdf.css` とした場合のpandocコマンドを下記に示します。

``` sh
pandoc _MD\\sample.md --to html5 --resource-path _MD\\ --embed-resources --standalone --css _HTML/github-markdown-light-custom4pdf.css --metadata title='sample' --output _HTML//sample.html
```

> ファイルパスの区切り文字は `/` または `\\` を使用します。`\` 一つはエスケープ文字として挙動するため、使用できません。

![run-pandoc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267641/45defcac-113b-c8ae-ba6a-ba3e5d432816.png)

この実行結果では、`WARNING` が表示されています。これは、`--metadata title="タイトル"` というオプションを付ければ解消しますが、これを付けるとHTMLファイルおよびPDFファイルの表紙ページの左上に強制的に`タイトル`に指定した文字列が表示されてしまうため、体裁上の観点から今回は無視することにしました。

本コマンドで使用しているPandocコマンドのオプションを説明します。上の例ではオプション記法の省略形は使わずに実行しています。

|Pandocオプション|省略形|引数|説明|
|:----|:----|:------|:------|
|なし|なし|Pandocの第一引数<br>Markdownファイルのパス・名前|変換対象となるMarkdownファイルまでのパス|
|--to|-t|html5|HTML5形式に変換する|
|--resouece-path|なし|フォルダ名|統合対象となる画像など（＝リソース）が入っているフォルダを探索する場所|
|--embed-resources|なし|なし|画像やCSSファイルなどをHTMLファイルに統合させる|
|--standalone|-s|なし|スタンドアロン文章（html,bodyタグがありそれ単体でドキュメントとして扱える文章）として生成する|
|--css|-c|cssファイルのパス・名前|HTMLのLinkタグで参照させるCSSファイルのパス|
|--output|-o|HTMLファイルのパス・名前|生成するファイル名|

pandocはこれ以外にも多数のオプションがありますが、ここでは今回の用途に必要十分なものだけを記載します。その他の詳細については、[公式サイトのリファレンス](https://pandoc-doc-ja.readthedocs.io/ja/latest/users-guide.html)をご覧ください。


## デザイン用CSSを適用するクラスを指定したdivの閉じタグを追記

[markdown-bodyクラスを適用したdivタグ](#・markdown-bodyクラスを適用したdivタグ) で説明した通り、HTMLファイルの冒頭（具体的にはbodyタグの直下）には、デザイン用CSSを適用するクラスを指定したdivタグが記述されています。ただし、このdivタグの閉じタグは生成されたHTMLファイルには存在しないため、明示的に記述しておきます。

実際には、ブラウザ表示やPDF生成においては、変換ツールやブラウザが上手いこと解釈して崩れなどの問題にはなりませんが、HTMLの作法上きれいにしておくという意味で、対処法を記載します。

MarkdownからHTMLに変換した直後は、次のような状態になっています。

``` html
</section>
</body>
</html>
```

これを下記のように書き換えます。

``` html
</section>
</div>
</body>
</html>
```

この書き換えは、下記のコマンドでも対処できます。

``` sh
sed -i -z 's/<\/body>\n<\/html>/<\/div>\n<\/body>\n<\/html>/g' _HTML//sample.html
```

## HTMLファイルをPDFに変換（wkhtmltopdfを利用）

ここまでで、`_HTML` フォルダに画像が統合された状態のHTMLファイルが格納された状態になりました。

このHTMLファイルに対して、`wkhtmltopdf` を利用することで、HTMLの見た目に沿ったPDFを作成することができます。

ここでは、先に作成したHTMLファイル `sample.html` 、それを変換したPDFファイル名を `sample.pdf` 、適用するcssファイルの名称を `github-markdown-light-custom4pdf.css` とした場合のwkhtmltopdfコマンドを下記に示します。下記コマンドでは付録として、各ページのフッター部分にcopyrightとページ番号を表示するオプションも追加しています。

``` sh
wkhtmltopdf --footer-left 'copyright hoge hige hanage.' --footer-right '[page]/[topage]' _HTML//sample.html _PDF//sample.pdf
```

![run-wkhtmltopdf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267641/fa2235f7-4ccc-b415-3c7c-d8ac8d1a6182.png)

|wkhtmltopdfオプション|引数|説明|
|:----|:----|:------|
|--footer-left|'copyright foobar company'|フッターの左部分にCopyrightを表記させる|
|--footer-right|'[page]/[topage]'|フッターの右部分にページ番号を表記させる|
|後ろから2個目の引数|入力HTMLファイル名|変換元となるHTMLファイルへのパス・ファイル名|
|後ろから1個目の引数|出力PDFファイル名|変換後のPDFファイルの格納先・ファイル名|

wkhtmltopdfについては、あまり公式サイトも読みやすくないためオプションなどは結構個別に調べたりして対処してました。そんな中でwkhtmltopdfのオプションを翻訳したBlogを見つけたので、備忘録もかねて謝辞の中にリンクを記載させていただきます。かんしゃあ！

## 謝辞

- CSSの元ファイル提供
  - @sindresorhus
  - https://github.com/sindresorhus/github-markdown-css

- CSSを利用した目次や見出しへの自動採番
  - @UKawamura
  - https://qiita.com/UKawamura/items/42f907c88686fb3be4da

- ユーザーエージェントリセットコードの提供
  - http://html5doctor.com/html-5-reset-stylesheet/

- wkhtmltopdf使用法の日本語訳
  - https://koukaforest.hatenablog.com/entry/2020/07/20/070000

本当に助かりました。ありがとうございます。