報告書をMarkdownで書いてpdfにしたいと思っていたところPandocを使うと良さそうだと知りました
Pandocはインストールが難しいらしいので、安易にdockerで構築しようと思い立って苦労しました。。。
LaTexは名前は知っていたのですが、学生時代はMSWordで論文を書いたため、ほぼゼロ知識だったのですが今回の構築を通して少し学べました

githubにまとめました

できること

MarkdownからPandocを用いて1コマンドで良い感じのPDFを生成すること  

できたもの

pandoc-latex/content.pdf at main · atooshi-note/pandoc-latex

特徴

  • Dockerで構築
  • pdf-defaults.yaml,header.texに設定を記載
  • pandoc-crossrefにより図表番号を自動入力(相互参照)
  • 目次のリンク機能
  • 章番号自動付与

defaults.yamlはpandoc2.8以降の機能です

環境

  • Windows10,11 macOS 12.6.8
  • Docker Desktop

Docker

> docker -v
Docker version 24.0.2, build cb74dfc

Pandoc

> docker run -it --entrypoint=/bin/sh --volume "$(pwd):/data" manned2665/pandoclatex311
/data # pandoc -v
pandoc 3.1.1
Features: +server +lua
Scripting engine: Lua 5.4
User data directory: /root/.local/share/pandoc
Copyright (C) 2006-2023 John MacFarlane. Web:  https://pandoc.org
This is free software; see the source for copying conditions. There is no
warranty, not even for merchantability or fitness for a particular purpose.

Pandoc-crossref

/data # pandoc-crossref -v
pandoc-crossref v0.3.15.1 git commit 6bc8fa67a4e1ada4787fa0ccd720a19e8e3c818e (HEAD) built with Pandoc v3.1.1, pandoc-types v1.23 and GHC 9.0.1

LuaLaTex

/data # lualatex -v
This is LuaHBTeX, Version 1.15.0 (TeX Live 2022)
Development id: 7509

Execute  'luahbtex --credits'  for credits and version details.

There is NO warranty. Redistribution of this software is covered by
the terms of the GNU General Public License, version 2 or (at your option)
any later version. For more information about these matters, see the file
named COPYING and the LuaTeX source.

LuaTeX is Copyright 2022 Taco Hoekwater and the LuaTeX Team.

TexLive 2022

/data # tlmgr version
tlmgr revision 63068 (2022-04-18 07:58:07 +0200)
tlmgr using installation: /opt/texlive/texdir
TeX Live (https://tug.org/texlive) version 2022

「tlmgr」とは「TeX Live Manager」の略

Linux : alpine 3.16.4

/data # cat /etc/alpine-release
3.16.4

ファイルのエンコード

Markdownファイルなど,全てUTF-8とします
shift-jisではエラーになります

Docker image

使用するにはまず、Docker imageを用意します
それには、Dockerfileをビルドするか,docker hubからイメージをpullします
両方同じなのでどちらでも良いです

DockerfileでベースにしたDocker imageは以下です
pandoc/latex - Docker Image | Docker Hub

pandoc/latexは2023年8月時点で最新のpandoc/latex:3.1.1をベースにして、日本語関係をインストールしています(tlmgr install collection-langjapanese)
pandoc-crossrefはPandocとバージョンを合わせる必要がありますが、pandoc/latex:3.1.1にはpandoc-crossrefが含まれているので新たにインストールは不要です

Dockerfileをビルド

Dockerfileがあるディレクトリにて,以下コマンドを実行します
Dockerfileはgithubにあげています
以下は例として
DockerfileがあるディレクトリはC:\Users
イメージ名 mypandoc でビルドした場合です

docker build -t mypandoc .

Dockerfileのビルドは初回のみ
次回以降は実行だけで良いです

docker hubからイメージをpull

実行するディレクトリはどこでも良いです

docker pull manned2665/pandoclatex311

PDF生成

docker pull manned2665/pandoclatex311したとして記載します
Docker Desktopを起動しておき,pdfにしたいmdファイルがあるディレクトリに移動して,以下を実行するとpdfが同じディレクトリに生成されます
(※Docker Desktopが未起動だとエラーになります) ディレクトリはC:\Usersと仮定します

docker run -it --rm --volume "$(pwd):/data" manned2665/pandoclatex311 -d pdf-defaults.yaml -M listings
  • インプットファイル名 content.md
  • アウトプットファイル名 content.pdf

インプット,アウトプットファイル名はpdf-defaults.yamlに記載してあります

もしくはコンテナを作成して起動して入ってシェルで実行します
pandoc/latex:3.1.1では、entrypointがpandocコマンドになっています pandocコマンド以外を使いたい場合、シェル上で操作するためにentrypointを/bin/shに上書きをします
なお、参考サイトで使用しているpandoc/latex:2.9.2.1はデフォルトでentrypointがshの様なので、上書きの操作は不要でした

> docker run -it --entrypoint=/bin/sh --volume "$(pwd):/data" manned2665/pandoclatex311
/data # pandoc -d pdf-defaults.yaml -M listings

フォント

フォントはフォントファイルを用意して、任意の場所に置き、pdf-defaults.yamlで指定することで適用できます

欧文フォントは以下で指定できます

  • mainfont
  • sansfont
  • monofont

和文フォントは以下で指定できます

  • CJKmainfont

CJK = Chinese Japanese Korean
当然ですが、フォントファイルに斜体,太字斜体が無ければ当然そうはなりません
例えばメイリオなら斜体,太字斜体は無いため,出力されたPDFでもそうはなりません
和文フォントには斜体、太字斜体があるものが少ないためコメントアウトしています

# pdf-defaults.yaml

variables:
  mainfont: times.ttf
  mainfontoptions:
    - Path=./fonts/
    - BoldFont=OpenSans-Bold.ttf
    - ItalicFont=timesi.ttf
    - BoldItalicFont=timesbi.ttf

  sansfont: FiraCode-Regular.ttf
  sansfontoptions:
    - Path=./fonts/

  monofont: Quicksand-Regular.ttf
  monofontoptions:
    - Path=./fonts/

  CJKmainfont: meiryo001.ttf
  CJKoptions:
    - Path=./fonts/
    - BoldFont=meiryob001_bold.ttf
    #- ItalicFont=meiryo002_ita.ttf
    #- BoldItalicFont=meiryob002_bold_ita.ttf

フォントはコンテナ内に入れる必要はありません
フォントの拡張子は以下が使えることを確認しています

  • .ttf(.ttcではない)
  • .otf

ttcはttfに分解して配置する必要あります

mdファイルと同じディレクトリに置くときの書き方は

# pdf-defaults.yaml

sansfont: FiraCode-Regular.ttf

でokです

./fontsにある場合は

# pdf-defaults.yaml

sansfont: FiraCode-Regular.ttf
sansfontoptions:
 - Path=./fonts/

和文フォントについてその他

CJKmainfontで指定する以外にluatexjapresetoptions:で指定する方法があります(これのほうが一般的かも??)
これにはコンテナ内にフォントがインストールされている必要がありますが、tlmgr install collection-langjapaneseしているので、大方の日本語フォントはインストールされています
CJKmainfontで指定している場合はCJKmainfontが優先される模様(これはpdf-defaults.yamlの記載順のせいかもしれないし、よく分かっていないです)
ゴシック体を使いたかったのですが,デフォルトは(私の環境では)luatexjapresetoptions: haranoajiとすると原ノ味明朝体が本文に適用されており、ゴシック体を指定する方法はわかりませんでした
このためluatexjapresetoptions:は使用していません
CJKmainfontで原ノ味(例えば,HaranoAjiGothic-Regular.otf)を指定するなら、luatexjapresetoptions: haranoajiはコメントアウトして良いです

以下は原ノ味(haranoaji)を指定している例

# pdf-defaults.yaml

# テンプレート変数
variables:
  lang: ja
  documentclass: ltjsarticle
  luatexjapresetoptions: haranoaji

原ノ味については以下
GitHub - trueroad/HaranoAjiFonts: 原ノ味フォント / Harano Aji Fonts

TeXLive2019には,haranoajiが入っていなかったので, tlmgr install collection-langjapanese でインストールが必要でした
TexLive2022には最初から入っているようです

フォント関連の参考

コードブロックでのあれこれ

コードブロックでうまくいかなかった事と解決策を記載します

コードブロックにlistings環境を適用するとエラーが発生する

エラー発生なし

{ .python .numberLines startFrom="10" caption="test.py"}
print("Hello World")

エラー発生

{ .python #lst:code .numberLines startFrom="10" caption="test.py"}
print("Hello World")

エラー内容

> docker run -it --rm --volume "$(pwd):/data" manned2665/pandoclatex311 -d pdf-defaults.yaml
Error producing PDF.
! LaTeX Error: Environment codelisting undefined.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...

l.234 \begin{codelisting}

原因
カスタムテンプレート
filterにpandoc-crossrefを使用しており、listingsと干渉しているため
Captions for code listings produce \begin{codelisting} which is not in the listings package · Issue #47 · lierdakil/pandoc-crossref · GitHub

解決方法
header-includesを使わない or -M listingsを追加する

docker run -it --rm --volume "$(pwd):/data" manned2665/pandoclatex311 -d pdf-defaults.yaml -M listings
# pdf-defaults.yaml

# テンプレート変数
variables:
  # 採番接頭辞・接尾辞の追加
  header-includes:
    - \renewcommand{\thesection}{第\arabic{section}章}
    - \renewcommand{\thesubsection}{第\arabic{subsection}節}
    - \renewcommand{\thesubsubsection}{第\arabic{subsubsection}項}

コードブロックで折り返しが効かず右に突き抜ける

PDF出力時にソースコードが長く、量が多い場合はdefaultでは折返しが効かず右を突き抜けてしまいます。また、下にはみだします

defaultは、 verbatimであり、listings を使うと自動折返しが可能です(ですがcontent.pdfを見ていただくとわかりますが、完全ではありません。未解決です。)
このためlistingsを使用したいのですが、上記した通りpandoc-crossref と listings は干渉して以下のエラーが発生します
同様に-M listingsをつけるとエラーを回避できます

verbatim でのコードブロック

\begin{verbatim}
code code code code code code code code
\end{verbatim}

listings でのコードブロック

\begin{lstlisting}
code code code code code code code code
\end{lstlisting}

エラー内容

> docker run -it --rm --volume "$(pwd):/data" manned2665/pandoclatex311 -d pdf-defaults.yaml
Error producing PDF.
! LaTeX Error: Environment lstlisting undefined.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...

l.133 \begin{lstlisting}

listingsの設定

自動折返しの設定などを含む細かい設定はheader.texに記載します
コマンドラインに -H header.tex をつける
か、default.yamlで呼び出します

-H header.tex をつけたパターン

docker run -it --rm --volume "$(pwd):/data" manned2665/pandoclatex311 -d pdf-defaults.yaml -M listings -H header.tex

default.yamlでheader.texをインクルードしたパターン
(コマンドラインに-H header.texは不要です)

# pdf-defaults.yaml

# ヘッダーファイルをインクルード
include-in-header: 
  - header.tex

listings: true
docker run -it --rm --volume "$(pwd):/data" manned2665/pandoclatex311 -d pdf-defaults.yaml -M listings

デバッグについて

pdf出力は時間がかかります
このため、texに一旦出力して、変更点が反映されたかチェックしてからpdfにしたほうが早いです(tex出力は早い)

PandocでMarkdown+Latexからpdfを出力する話 - Qiita

もし、Latexまわりでエラーが出た場合はdefaults.yaml内のoutput-file:desc.texに変え、standalone: trueを追加するとtexファイルが生成されるためエラー箇所が見つけやすいと思います。

# 出力ファイル (単一アイテムで指定)
output-file: content.tex

参考

Pandocマニュアル