Pandoc+Dockerでドキュメント作成環境を整備する
Pandoc、MarkdownからHTMLでもPDFでも、Wordにだって出力できて便利ですね。
軽い気持ちでPandocを導入しようとしたら地獄を見たのでその備忘録です。
なお、筆者の環境は Windows10 Pro + Docker for Windows で構築しています。 Linux歴3週間程度のため、コマンドの打ち方等は未熟な部分がありますのでご容赦ください。
2020/7/27 17:00 更新 HTMLの見出しの採番用Luaフィルタを追加
リポジトリを作成しました。
目的
和文MarkdownからPDF及びHTMLを出力することを目的とします。
概要
Docker上にPandocの環境を構築します。
最終的に、次のコマンドでPDFやHTMLの出力ができるようにします。
# ワンライナーで出力する場合 > docker run -rm --volume "$(pwd):/data" mypandoc -d xxx-defaults.yaml # 一度コンテナ内に入ってから出力する場合 > docker run -it --volume "$(pwd):/data" mypandoc /bin/sh $ pandoc -d xxx-defaults.yaml
手順
下記の手順にてPandocの環境を整備していきます。
- Docker (Docker for Windows)をインストールする
- pandoc/latexイメージを導入する
- 和文Markdownに対応するため、LuaTeXパッケージ等導入する
- 図表対応のため pandoc-crossref を導入する
- 簡単にきれいな見た目のHTMLを出力するため、easy-pandoc-templateを導入する
- 上記をまとめたDockerfileを作成する
- 長いオプションをDefault fileにまとめる
- 補足:採番の接頭辞・接尾辞を修正する(PDFとHTMLの2パターン)
Docker (Docker for Windows)をインストールする
最初にDockerをインストールします。
> docker -v
Docker version 19.03.8, build afacb8b
バージョンが返ってくればOKです。 Dockerの操作方法が分からない方には、わかばちゃんシリーズのDocker本をおすすめします。 私はほとんどこれしか読んでません(ぇ
なお、本ブログではコマンドの実行を>
と$
で区別します。
> docker ... ← PowerShell上のコマンド $ pandoc ... ← Dockerコンテナ上のコマンド
pandoc/latexイメージを導入する
pandocとlatexが構築されている神Dockerイメージがあるので、これを利用します。
latestだと随時更新されてしまうため、現時点の最新版である2.9.2.1を使用します。 ちなみにディストリビューションはalpineっぽいです。
> docker run -it --volume "$(pwd):/data" pandoc/latex:2.9.2.1 /bin/sh $ ls contents.md etc... $ pandoc -v pandoc 2.9.2.1 etc... $ cat /etc/alpine-release 3.11.5
ここで、次のcontents.md
をカレントディレクトリに作成し、pandocでpdfにコンパイルしてやります。
# contents contents. 本文だよ
$ pandoc contents.md -o conetnts.pdf Error producing PDF. ! Package inputenc Error: Unicode character 本 (U+672C) ... Try running pandoc with --pdf-engine=xelatex.
pandoc/latexはそのままでは日本語フォントを読むことができません。 そこで、次にLuaTeXやIPAフォントパッケージ等を導入します。
LuaTeXパッケージ等導入する
次のパッケージをまとめてインストールします。
tlmgr
というTeXLiveのパッケージマネージャが既に入ってるので、これを利用します。
$ tlmgr install ipaex luatexja
$ tlmgr update latex
# 以下必要に応じて
$ tlmgr install bxjscls bxwareki everyhook svn-prov type1cm
参照:pandoc/latexをいじって日本語LaTeXできるようにしたやつ · GitHub
ipaex luatexja
パッケージをインストールすれば、和文のコンパイルはできます。
次のコマンドでカレントディレクトリにPDFが出力されることを確認してください。
$ pandoc contents.md -o contents.pdf --pdf-engine=lualatex -V documentclass=ltjsarticle
図表対応のため pandoc-crossref を導入する
図や表のキャプション(図1, 表1など)を簡単に付けてくれるpandoc-crossrefを導入します。
$ wget -O - https://github.com/lierdakil/pandoc-crossref/releases/download/v0.3.6.4/pandoc-crossref-Linux-2.9.2.1.tar.xz | \ tar Jxf - \ && mv pandoc-crossref /usr/lib/ && rm -rf pandoc-crossref.1
いちいち保存せずに、tarにパイプして処理できるの楽ちんですね。
contents.md
に次のように記述することで、キャプションの相互参照が可能になります。
# contents contents. 本文だよ ![すごい図](./images/test.png){#fig:sugoi} すごい[@fig:sugoi]を貼り付けたよ。
$ pandoc contents.md -o contents.pdf --pdf-engine=lualatex -V documentclass=ltjsarticle --filter pandoc-crossref
だんだんオプションが長くなってきました。後ほどオプションをyamlファイルに切り出します。 出力されたPDFはこうなります。
Fig.1等の記述は、contents.md
の最初にyaml形式でメタデータを記述することにより修正できます。
--- figureTitle: "図 " tableTitle: "表 " listingTitle: "コード " figPrefix: "図." eqnPrefix: "式." tblPrefix: "表." lstPrefix: "コード." --- # contents ...
PDF形式への出力に必要な操作は以上となります。 次にHTML出力を行います。
easy-pandoc-templatesを導入する
pandocでHTMLに出力する場合、ただ出力するだけなら次のワンライナーでOKです。 ただしものすごく味気ないスタイルになります。
$ pandoc contents.md -o contents.html --filter /usr/lib/pandoc-crossref
比較的簡単に、きれいなHTMLを出力するため、easy-pandoc-templatesを導入します。
$ wget -O - https://github.com/ryangrose/easy-pandoc-templates/archive/master.tar.gz | \ tar zxvf - -C /usr/lib/
easy-pandoc-templates-master/html/elegant_bootstrap_menu.html
が使用するHTMLのテンプレートです。
--toc
オプション(table-of-contents: 目次)を付与することで、左側に見出しの一覧が表示されるようになります。
また、--metadata title
を指定していないと警告が表示されるので、オプションで指定します。
$ pandoc contents.md -o contents.html --toc --template=/usr/lib/easy-pandoc-templates/html/elegant_bootstrap_menu.html --filter /usr/lib/pandoc-crossref --metadata title=すごい記事
Dockerfileを作成する
ここまでいろいろツールをインストールしてきましたが、Dockerイメージを作る段階で全て導入してしまいましょう。 pandoc/latex:2.9.2.1をベースにDockerfileを作成します。
# Dockerfile FROM pandoc/latex:2.9.2.1 RUN tlmgr install \ bxjscls \ bxwareki \ everyhook \ ipaex \ luatexja \ svn-prov \ type1cm && \ tlmgr update latex RUN wget -O - https://github.com/lierdakil/pandoc-crossref/releases/download/v0.3.6.4/pandoc-crossref-Linux-2.9.2.1.tar.xz | \ tar Jxf - \ && mv pandoc-crossref /usr/lib/ \ && rm -rf pandoc-crossref.1 RUN wget -O - https://github.com/ryangrose/easy-pandoc-templates/archive/master.tar.gz | \ tar zxvf - -C /tmp/ \ && mv /tmp/easy-pandoc-templates* /usr/lib/easy-pandoc-templates \ && rm -rf /tmp/*
このDockerfileを基にイメージをコンパイルします。 イメージ名(mypandoc)は適当に指定してください。
> docker build -t mypandoc .
使い方は次のとおりです。
> docker run -rm --volume "$(pwd):/data" mypandoc ...どちゃくそ長いオプション
オプションが長いので、Pandoc 2.8で解禁されたDefault fileを定義します。
長いオプションをDefault fileにまとめる
オプションを次のとおりyaml形式でまとめます。
# xxx-defaults.yaml # 入力ファイル(複数の入力も可) input-files: - content.md - content2.md - content3.md # 出力ファイル (単一で指定) output-file: content.pdf # --pdf-engine オプション pdf-engine: lualatex # テンプレート変数 variables: documentclass: ltjsarticle classoption: pandoc # 字下げ indent: true # 余白 geometry: - top=20mm - right=24mm - left=24mm - bottom=20mm - heightrounded # 採番接頭辞・接尾辞の追加(HTML用のyamlでは削除) header-includes: - \renewcommand{\thesection}{第\arabic{section}章} - \renewcommand{\thesubsection}{第\arabic{subsection}節} - \renewcommand{\thesubsubsection}{第\arabic{subsubsection}項} # HTML用のテンプレートファイル(PDF用のyamlでは削除) template: /usr/lib/easy-pandoc-templates-master/html/elegant_bootstrap_menu.html # メタデータ metadata: title: すごい記事 figureTitle: "図 " tableTitle: "表 " listingTitle: "コード " figPrefix: "図." eqnPrefix: "式." tblPrefix: "表." lstPrefix: "コード." # 目次 table-of-contents: true # 目次出しの深さ toc-depth: 2 # 見出しの採番 number-sections: true # 各種フィルタ filters: - /usr/lib/pandoc-crossref
使用するときは-d
オプションでyamlを指定します。だいぶすっきりしました。
> docker run -rm --volume "$(pwd):/data" mypandoc -d xxx-defaults.yaml # またはコンテナを起動して $ pandoc -d xxx-defaults.yaml
以上で和文MarkdownからPDF及びHTMLの出力は完了です。
補足:採番の接頭辞・接尾辞の修正
デフォルトでは、見出しの採番は次のようなフォーマットになります。
# 見出し1 ## サブ見出し # 見出し2 ## サブ見出し ↓ 1. 見出し1 1.1 サブ見出し 2. 見出し2 2.1 サブ見出し
ここに接頭辞・接尾辞を追加する場合、PDFとHTMLとで次のように処理を分けます。
PDF出力の場合
テンプレート変数のheader-include
に次のように記述します。
variables: header-includes: - \renewcommand{\thesection}{第\arabic{section}章} - \renewcommand{\thesubsection}{第\arabic{subsection}節} - \renewcommand{\thesubsubsection}{第\arabic{subsubsection}項}
# 見出し1 ## サブ見出し # 見出し2 ## サブ見出し ↓ 第1章 見出し1 第1節 サブ見出し 第2章 見出し2 第1節 サブ見出し
HTML出力の場合(easy-pandoc-templates使用を前提)
easy-pandoc-templates-master/css/elegant_bootstrap.css
に次の記述を追加します。
疑似要素(::before, ::after)を使って見た目だけ変えてやる形です。
forkして修正するなら、rawgit
がHTMLテンプレート中に記述されているのでjsdelivr
に書き換えればより安全です。
h1 > span.header-section-number::before{ content: "第"; } h1 > span.header-section-number::after{ content: "章"; } h2 > span.header-section-number::after{ content: "節"; }
# 見出し1 ## サブ見出し # 見出し2 ## サブ見出し ↓ 第1章 見出し1 1.1節 サブ見出し 第2章 見出し2 2.1節 サブ見出し
HTMLではサブ見出しの採番の修正がうまくいってません。
「第1節」のように「1.」だけを消す方法があればお教えください。
どうやら、Pandocがつける節番号は、Header値の“number”という属性値を設定すれば変えられるようなので、それを利用すればLuaフィルタでどうにかなるらしい。#ぱんどっく https://t.co/i32WAzZUBP
— 某ZR(ざんねん🙃) (@zr_tex8r) 2020年7月27日
zr_tex8r氏にとんでもねぇ速度で解決していただきました。
numberring.lua
を作成し、filters: - numberring.lua
で追加すればOK。
参考にさせていただいたサイト
他にもまだまだありますが、ネットの海に沈んでしまいました(´・ω・`)