モダンなLaTexで書いたレポートを簡単にdockerでPDFに変換してCIで配布する方法

![output.gif](https://qiita-image-store.s3.amazonaws.com/0/25325/2bbfe286-b318-dc9f-83d1-5a77c82aa49a.gif)

# TL;DR
dockerがインストールされているPCで

```bash
docker pull eisoku9618/latex:latex-japanese
cd /path/to/target_dir
docker run --rm -it --user=`id -u $USER` -w=/root -v $(pwd):/root eisoku9618/latex:latex-japanese /bin/bash -c "latexmk -pvc main.tex"
evince /path/to/target_dir/.tmp/main.pdf
```
をすると，上のgifのように生成されるPDFを見ながらソースとなるtexを編集することが出来る．
そして，texファイルが完成したら，
PDFはコミットせずtexファイルのみをgitlabにコミットすることで，
gitlab-ciが回って，上記と同じ手順で最新のtexファイルをPDFに変換し，それをブラウザで見れるようにしてくれる．
例えば， https://gitlab.com/eisoku9618/report のREADME.mdから以下のようにPDFを閲覧できる．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/25325/8dd6f0e9-9b52-7421-51ef-45523f77446d.png)


### 特徴のまとめ

2019/11/24追記： notoフォントを使うとdocker imageが大きくなるので，より軽いかつ日本語なipaexフォントを使うようにした．

| ポイント | 参考サイト |
|:-----------------|------------------:|
| ~~日本語フォントにNotoフォントを使う~~ | ~~[Google Noto Fonts](https://www.google.com/get/noto/)~~ |
| 日本語フォントが埋め込まれたPDFを生成する | [upLaTeX文書で源ノ明朝／Noto Serif CJKを簡単に使う方法（最新のdvipdfmxとpxchfonを使用）](https://qiita.com/zr_tex8r/items/9dfeafecca2d091abd02) |
| texを更新する度にPDFを自動で再生成する | [数式ありのレポートや本をモダンに書く](https://qiita.com/eisoku9618/items/4dccadf48f0232b3b336) |
| 必要な環境はdockerで構築してポータブルにする | [DockerhubのAutomated buildを試す](https://qiita.com/jagaximo/items/4cbda778a10fd37f68e6) |
| texファイルのみをgit管理下において，PDFはブラウザから閲覧できるようにする | [Introduction to job artifacts](https://docs.gitlab.com/ee/user/project/pipelines/job_artifacts.html) |


# 設定手順
ここでは，上記を実現するための手順を備忘録として書いておく．

### ~~STEP0: 日本語フォントにNotoフォントを使う~~
texで簡単に使える日本語フォントとしては，デフォルト（texlive-lang-japanese）でインストールされるIPAフォントまたはIPAexフォントがあるが，IPA/IPAexを埋め込んだPDFをブラウザで閲覧すると日本語が表示されないことがある．
詳細は分かっていないが`pdffonts hoge.pdf`したときに`uni`の列が`No`になっている場合はそうなるらしい．

- http://hmdt.jp/blog/?p=738

そこで，notoフォントをインストール（`apt`で入る）して，それを埋め込むと，`pdffonts`の結果が次のようになって，`uni`の列が`Yes`になって，ブラウザから見た時にも日本語が表示されるようになる！
STEP4でPDFをブラウザで閲覧できるようになるので，IPAフォントではなくてnotoフォントを使うことにする．
※ フォント自体にこだわりはなくて，インストールが簡単，かつ，`uni`が`Yes`になるフォントであれば何でも良い

```bash:pdffontsの結果
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
QYAGJC+NotoSerifCJKjp-Regular-Identity-H CID Type 0C       Identity-H       yes yes yes      5  0
```



### STEP1: 日本語フォントが埋め込まれたPDFを生成する
[upLaTeX文書で源ノ明朝／Noto Serif CJKを簡単に使う方法（最新のdvipdfmxとpxchfonを使用）](https://qiita.com/zr_tex8r/items/9dfeafecca2d091abd02)で詳しく説明されているように，TeX Live 2017からdvipdfmxが新しくなり，noto/ipaexフォントを埋め込むまでの手順が簡単になった．

- ※ それまでのdvipdfmxではどのくらい大変だったかは[(u)pLaTeXのデフォルトの日本語フォントを好きなやつに変える方法](https://qiita.com/zr_tex8r/items/15ec2848371ec19d45ed)で詳しく説明されている．

例えばUbuntu 16.04だとTex Liveは2015なのでNGで，
Ubuntu 18.04だと2017になってOK．
よって，Ubuntu 18.04にて次のコマンドでuplatexとnotoフォントをインストールすればOK．
また，`apt`で入れるだけでnoto/ipaexフォントが「TeXから見える状態」になっているので簡単．

```bash:(STEP3でDockerにするので次のパッケージを手元でインストールする必要はない)
sudo apt install texlive-lang-japanese # (u)platexをインストールする
sudo apt install fonts-noto-cjk fonts-noto-cjk-extra # noto fontをインストールする
sudo apt install fonts-ipaexfont-gothic fonts-ipaexfont-mincho # ipaex fontをインストールする
```

### STEP2: texを更新する度にPDFを自動で再生成する
texをPDFにするには

- `uplatex main.tex`
- `dvipdfmx main.dvi`

のようにコマンドを複数回打つ必要がある．
さらに，`cite`，`ref`があると打つ必要があるコマンドが増えていく．

これでは大変なので，Makefileを自分で作って簡略化する方法があるが，
よりモダンにするには`latexmk`というプログラムを使うのが良いっぽい．
詳しくは[数式ありのレポートや本をモダンに書く](https://qiita.com/eisoku9618/items/4dccadf48f0232b3b336)に書いてある．

- `latexmk`は`apt`でインストールできる．



### STEP3: 必要な環境はdockerで構築してポータブルにする
STEP0からSTEP2までの内容を手元のPCでやるには大変（dvipdfmxが新しい必要があってUbuntuなら18.04が必要，手元のPCの環境が汚れる，他の人のPCでやるときに0から設定するのは面倒，，，）なので，Dockerで環境構築をして，手元のtexファイルをそのDockerコンテナにマウントしつつ，PDFを生成するのがモダン．

```dockerfile:Dockerfile
FROM ubuntu:18.04

ENV DEBIAN_FRONTEND noninteractive

RUN apt update && apt install -y --no-install-recommends \
# for (u)platex
texlive-lang-japanese \
# for CTAN packages
texlive-plain-generic texlive-latex-base texlive-latex-extra \
# for latexmk
latexmk \
# for noto font: Bold and Regular
fonts-noto-cjk \
# for noto font: Black, DemiLight, Light, Medium, Thin and so on
fonts-noto-cjk-extra \
&& rm -rf /var/lib/apt/lists/*

CMD ["/bin/bash"]
```

確認のために

```bash
docker build -t test_container ./
docker run --rm -it test_container /bin/bash
```
してDockerコンテナに入って

- ``kpsewhich NotoSerifCJK-Black.ttc ``: Notフォントが認識されていることが分かる
- ``kanji-config-updmap status``: デフォルトのフォントを変更していないことが分かる（``CURRENT family for ja: noEmbed``）
   - notoフォントはtexファイルにて``\usepackage[noto-otc, unicode]{pxchfon}``とすることで使用するため．

![image.png](https://qiita-image-store.s3.amazonaws.com/0/25325/86d8fbfa-0d33-b04a-647d-43ae881c1cfd.png)

とすると確認できるし，

```tex:/tmp/test.tex
\documentclass[uplatex]{jsarticle}
\usepackage[ipaex, unicode]{pxchfon}

\begin{document}
ハローワールド．
\end{document}
```

というtexファイルを手下に作り

```bash
docker run --rm -it --user=`id -u $USER` -w=/root -v /tmp:/root test_container /bin/bash
uplatex test.tex
dvipdfmx test.dvi
```

のように手元のPCの"/tmp"をコンテナにマウントして，``uplatex``と``dvipdfmx``を行うと，
手元のPCに"/tmp/test.pdf"が生成される．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/25325/3681a22a-d8b0-ff7d-7819-7187ca811c4f.png)

また，

```rb:/tmp/.latexmkrc
#!/usr/bin/env perl
$latex            = 'uplatex -halt-on-error -file-line-error %O %S';
$out_dir          = '.tmp';
$bibtex           = 'upbibtex';
$dvipdf           = 'dvipdfmx %O -o %D %S';
$makeindex        = 'upmendex %O -o %D %S';
$max_repeat       = 5;
$pdf_mode	  = 3; # generates pdf via dvipdfmx

# Prevent latexmk from removing PDF after typeset.
# This enables Skim to chase the update in PDF automatically.
$pvc_view_file_via_temporary = 0;

$view	    = 'none';
```

のような``latexmk``の設定ファイルを手元の"/tmp"に作り，

```bash
docker run --rm -it --user=`id -u $USER` -w=/root -v /tmp:/root test_container /bin/bash -c "latexmk -pvc test.tex"
```

すると，texが更新される度に`/tmp/.tmp/test.pdf`も更新されるようになる．
![output.gif](https://qiita-image-store.s3.amazonaws.com/0/25325/2bbfe286-b318-dc9f-83d1-5a77c82aa49a.gif)


また，上記のDockerイメージをdockerhubに置いたものが[eisoku9618/latex](https://hub.docker.com/r/eisoku9618/latex)になるので，

```bash
docker pull eisoku9618/latex:latex-japanese
```
とすればSTEP0から3で構築した環境をコマンド1つで構築することが出来る．

- Ubuntu 16.04でもTex Live 2017を使える
- 手元のPCの環境は汚れない
- 他の人のPCでもすぐに環境構築できる


### STEP4: texファイルのみをgit管理下において，PDFはブラウザから閲覧できるようにする

https://gitlab.com/eisoku9618/report に具体例を置いた．

このレポジトリにはバイナリである`.pdf`はコミットしていないが，
gtilab-ciの設定を次のようにすることでコミットされた`.tex`をPDFにして所定の場所に置いてくれる．

```yaml:.gitlab-ci.yml
services:
  - docker:dind

latex_job:
  image: eisoku9618/latex:latex-japanese
  script:
    - (for dir in *; do [ -d "${dir}" ] && echo "$dir start" && (cd $dir && latexmk main.tex && mv .tmp/main.pdf ../${dir}.pdf); done)
  artifacts:
    expire_in: 2 days
    paths:
      - ./*.pdf
```
- https://gitlab.com/eisoku9618/report/blob/master/.gitlab-ci.yml

その所定の場所はREADME.mdに書かれており，以下のようにPDFをブラウザから閲覧できるようになる．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/25325/8dd6f0e9-9b52-7421-51ef-45523f77446d.png)

gitlab-ciの成果物は一定期間経過すると消されてしまうらしいが，
次のように毎日4時にorigin/masterでCIを走らせるようにすることで，
常に最新のPDFを閲覧できるようにすることができる．

![image.png](https://qiita-image-store.s3.amazonaws.com/0/25325/db52d605-357b-ee98-9903-8b51648f289d.png)