この記事は、 JSL(日本システム技研) Advent Calendar 2020 - Qiita 12/8の記事です。
以前、markdownからpdfを作成する機会がありました。
GitLab CI + docker-reviewを使って、Markdownをtextlintしてからpdf化するCI環境を作ってみた - メモ的な思考的な
他の方法がないかを見たところ、 pandoc & wkhtmltopdfでも作成できそうでした。
pandoc + markdownでいい感じの執筆環境を作る - Qiita
そこで、pandoc & wkhtmltopdf のDockerイメージを作成し、複数マークダウンファイルを1つのpdfにしてみました。
目次
環境
- Docker
- 以下のライブラリを入れる
- pandoc 2.11.2
- wkhtmltopdf 0.12.5
- フォントは Google Noto
- 以下のライブラリを入れる
最終的なディレクトリ構成はこちら。
$ tree . ├── Dockerfile ├── manuscript │ ├── りんご.md │ └── さつまいも.md ├── output │ └── (merge.pdf) └── settings ├── defaults.yaml └── style.css
マークダウンファイルは2つ用意しました。
なお、マークダウンファイル内で \
の後にトリプルバッククォートしている部分ですが、はてなブログに貼るために書いているため、本来 \
は不要です。
りんご.md
# りんごの種類 - シナノゴールド - フジ (以下の \ は不要) \```python print('りんごです!') \``` <div class="hidden"> # コメント シナノゴールドはイタリアをはじめとした海外に進出してる </div> <div class="page-break"></div>
さつまいも.md
# さつまいもの種類 - 紅はるか - 安納芋 (以下の \ は不要) \```python print('さつまいもです!') \``` <div class="hidden"> # コメント 紅優甘は、紅はるかの商標登録名 </div> <div class="page-break"></div>
実装
Dockerfile
同じようなDockerfileがないかを探したところ、以下のリポジトリがありました。
https://github.com/slurdge/docker-pandoc-wkhtmltopdf
ただ、docker buildしてみると
E: Package 'libssl1.0-dev' has no installation candidate
というエラーでビルドできませんでした。
他のDockerfileがないかを探したところ、 wkhtmltopdf を使っているDockerfileがありました。
Docker コンテナ上で wkhtmltopdf を動かす - Qiita
そこで、これらを組み合わせて作ってみることにしました。
まずはpandocのリポジトリを見たところ、 pandoc-2.11.2-1-amd64.deb
がありました。
https://github.com/jgm/pandoc/releases/
次にwkhtmltopdfのリポジトリを見たところ、 wkhtmltox_0.12.5-1.buster_amd64.deb
等のdebファイルがありました。
https://github.com/wkhtmltopdf/wkhtmltopdf/releases
そこで、今回はDebianベースで作ることにしました。
ただ、上記だけでは日本語を含んだマークダウンが文字化けしてしまいました。
そこで「Docker コンテナ上で wkhtmltopdf を動かす」の記事に合わせてフォントを入れることにしました。
DebianでNotoフォントを入れる方法を探したところ、 fonts-noto-cjk
と fonts-noto-cjk-extra
を使えば良さそうでした。
Linuxだって、綺麗にフォントが表示できるんだからねッ!
そのため、pandocとwkhtmltopdfはGithubから、それ以外はdebファイルからインストールすることにしました。
ただ、debファイルからインストールする際にいくつか依存関係が発生することから、 gdebi
もインストールしておきます。
他に、 --no-install-recommends
でインストールすると
ERROR: The certificate of 'github.com' is not trusted. ERROR: The certificate of 'github.com' doesn't have a known issuer.
が発生することから、 ca-certificates
も追加しています。
Ubuntu on Docker で SSL/TLS 通信するとエラーになる問題の対処 - Qiita
最終的なDockerfileはこちら
FROM debian:buster-slim RUN apt-get update && apt-get install -y --no-install-recommends \ xorg \ libssl-dev \ libxrender-dev \ wget \ gdebi \ fonts-noto-cjk \ fonts-noto-cjk-extra \ ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && apt-get autoremove \ && apt-get clean RUN wget https://github.com/jgm/pandoc/releases/download/2.11.2/pandoc-2.11.2-1-amd64.deb -O pandoc.deb \ && dpkg -i ./pandoc.deb \ && rm pandoc.deb RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.buster_amd64.deb -O wkhtmltox.deb \ && dpkg -i ./wkhtmltox.deb \ && rm wkhtmltox.deb RUN mkdir /var/tmp/output
docker build
Dockerfileができたのでビルドします。
$ docker build ./ -t pandoc_wkhtmltopdf:1.0 ... Successfully built ae80e0763df1 Successfully tagged mydoc:1.0
ビルド後のサイズはこんな感じです。
$ docker image list pandoc* REPOSITORY TAG IMAGE ID CREATED SIZE pandoc_wkhtmltopdf 1.0 ae80e0763df1 2 minutes ago 998MB
docker run
Dockerイメージができたので、docker run します。
オプションとして以下を指定します。
オプション | 内容 |
---|---|
--mount type=bind,src=...,dst=... |
ホストとDockerでファイルを共有するため。生成したpdfのコピーを不要にする |
-w /var/tmp/output |
作業ディレクトリをホストと共有したディレクトリにすることで、cdとか不要に |
docker run後、Dockerに入って作業ディレクトリにいればOKです。
$ docker run -it --mount type=bind,src="$(pwd)"/,dst=/var/tmp/output -w /var/tmp/output --name mypandoc pandoc_wkhtmltopdf:1.0 ... root@f190aac6d170:/var/tmp/output#
pandocとwkhtmltopdfによる変換
Default filesファイルを作成
pandoc実行時にオプションを渡してpdfファイルへと変換します。
ただ、pandocにはオプションが多くあるため、実行時に指定漏れが発生しそうでした。
そこで、Default filesを使って、コマンド時のオプションは必要最低限とすることにしました。
https://pandoc.org/MANUAL.html#default-files
なお、今回複数マークダウンファイルを1つのpdfにまとめますが、 input-files
ではワイルドカード指定ができなかったため、Default filesには記載しませんでした。
Wildcard for multiple input files in the defaults file variable "input-files" - Google グループ
from: markdown to: html5 # 入力ファイルはコマンドラインから指定 # manuscript/*.md が指定できないため # 出力ファイル (単一で指定) output-file: output/merge.pdf # コードブロックの背景色 highlight-style: tango # 独自CSS css: - settings/style.css
独自CSSファイルの用意
今回は改ページと非表示のclassを用意しました。
.page-break { page-break-before: always; } .hidden { display: none; }
pandocコマンドの実行
pandocコマンドで変換を行います。
# pandoc ./manuscript/*.md -d settings/defaults.yaml [WARNING] This document format requires a nonempty <title> element. Defaulting to 'さつまいも' as the title. To specify a title, use 'title' in metadata or --metadata title="...". Loading pages (1/6) Counting pages (2/6) Resolving links (4/6) Loading headers and footers (5/6) Printing pages (6/6) Done
pdfの確認
改ページされていること、不要な部分が表示されていないことが確認できました。
ソースコード
Githubに上げました。
https://github.com/thinkAmi-sandbox/pandoc_wkhtmltopdf_docker
その他参考
aptまわり
- apt - What is difference between the options "autoclean", "autoremove" and "clean"? - Ask Ubuntu
- Dockerfile に apt, apt-get, source コマンドを書く時のTips | cloud.config Tech Blog
- apt - gdebi vs dpkg : How does gdebi automatically gets missing dependancies ? Can I use gdebi for all other installations of .deb packages? - Ask Ubuntu