feature image

2020年9月29日 | ブログ記事

MarkdownとPandocとLatexmkで楽してレポートを書く

こんにちは、@d_etteiu8383です。この記事はtraP夏のブログリレー9月29日の記事です。
この記事では私のレポート制作環境(PandocとLatexmkを使ったPDF作成の自動化)の紹介をします。
既に似た内容の記事が多く存在するため新規性の無い記事ではありますが、皆さんの参考になったら幸いです。

1 目的

以下この記事を書こうと思った経緯↓

  1. コロナウィルスの影響により、私が所属している系の必修科目である実験科目が延期される
  2. 夏季期間講義として(夏休みを削って)本来のスケジュールを圧縮して週四回の実験科目が開講されることになる
  3. 週四回以上のレポート提出を要求される
  4. くるしい

普段はWordか を用いてレポートを書いていたのですが、Word文書の見た目を整えるのが苦手だったり、そもそもWord自体動作が重かったり、 はコマンド書くのが大変だったりして、レポート1つ仕上げるのに非常に時間がかかっていました。そこでレポートの制作環境を見直し、ここにまとめることにしました。手書き、 直書き、Wordで作る...いろいろ手段はあると思いますが、「そういう方法もあるんだなぁ」程度に読んでもらえると嬉しいです。ここでは最低限講義レポートととして提出できるレベルのPDFファイルを(なるべく楽して)出力することを目的とします。

レポートに追われながら書いているので(特に後半)かなり雑な記事になってしまっています。わかりづらい点などありましたらコメントで教えてもらえるとありがたいです。レポート倒したら必ず更新しに来ます。

環境

2 原理

以下の手順でレポートを作成していきます。(ほとんどhttps://blog.8tak4.com/post/168232661994/know-how-writing-thesis-markdownで紹介されている手順を参考にしているのでこちらを見ていただいたほうがわかりやすいかもしれません...)

  1. Markdownでレポート本文を書く
  2. BibTeXで文献情報をまとめる
  3. Pandocで1のMarkdownファイルをtexファイルに変換する
  4. 3のtexファイルからLatexmkを使ってPDFを作成する
  5. (表紙PDFが指定されている場合)Pythonで表紙PDFと結合

以下で各手順の概要を説明します。環境構築や実際に作成するファイルの内容は 3 方法 で紹介します。

Markdownでレポート本文を書く

まず初めに、読み書きが非常に楽なMarkdown記法を用いてレポート本文を作成します。Markdownのコマンドは に比べて非常に簡単なので、コマンドミス等に気を取られずレポート本文に集中して執筆ができます。実はこのブログ記事もMarkdown記法を用いて執筆しています。めっちゃ楽。Markdownを使う事のメリットとしては、git diff等で差分の確認が簡単にできることも挙げられます。MSWordのdocx形式はバイナリ形式なのでテキストに変換しないとdiffが見れないです。

具体的なコマンドやMarkdownの活用法についてまとまっているこちらの記事もぜひご覧ください↓

情報系以外の方にもおすすめしたいMarkdown
こんにちは、こちらはtraP新歓ブログリレー2018 4月16日の記事になります。担当の60°です。 新入生の皆さん、ご入学おめでとうございます。 大学では、レポートを書いたり話し合いの議事録をとったりなど、PCを使って文書を作成する機会が多くあります。中には、授業ノートをPCでとろうと考えている方もいるかもしれません。 そんなときに是非おすすめしたいのが、今回お話しするMarkdownです。 この記事では、Markdownを知らない方や使ったことがない方に向けて、その特徴や使い方について説明しています。 内容は以下の通りになっています。 それなりに長いので、気になったところだけを飛ば…

本記事とは関係ない話ですが、弊サークルの部内SNS traQ[1]ではメッセージ中でMarkdown記法を利用できます。すごい。

BibTeXで文献情報をまとめる

BibTeXとは、 における参考文献の整形ツールです。.bibの拡張子を持つ参考文献の情報を記述したファイルを作成することで、著者名等を自動で整形し、相互参照(後述)したうえで適切に出力してくれます。

PandocでMarkdownファイルをtexファイルに変換する

Markdownは本来プレーンテキスト形式で書かれた文章からHTMLを生成するために開発されたものでした。しかし、現在ではHTML以外の形式のファイルへ変換するソフトも多数存在します。今回はその1つであるPandocというコンバータを用いてMarkdownファイルからtexファイルへの変換を行います。

Pandocの仕組み

そもそもPandocはMarkdownや に限らず、HTMLやWordなど多種多様なフォーマット間の変換が可能なツールです。対応フォーマットの一覧や、より詳しい使い方については公式ページや、
Pandocユーザーズガイド 日本語版をご覧ください。

Pandocは以下のような手順で文書を変換しています。(https://github.com/jgm/pandoc/blob/master/README.md より引用)

Pandoc has a modular design: it consists of a set of readers, which parse text in a given format and produce a native representation of the document (an abstract syntax tree or AST), and a set of writers, which convert this native representation into a target format. Thus, adding an input or output format requires only adding a reader or writer.

まずPandocは入力された変換前の文書を、リーダーというプログラムを用いて抽象構文木(abstract syntax tree, AST)と呼ばれる形式に変換します。抽象構文木についておおざっぱに説明すると「もとの文章の意味を保持したまま、その各要素を種類によって区別し(見出しなのか?本文なのか?表なのか?図なのか?など)、いい感じに整理整頓したもの」といった感じ。次にライターというプログラムを用い、この抽象構文木を指定の出力形式に変換します。つまりPandocは入力文書を直接出力形式に変換しているのではなく、一度汎用的な形式に変換してから再度目的形式に変換する、という二度の変換を行っています。リーダーとライターを分けているので、新しい形式を利用したい場合は必要なリーダー/ライターを追加するだけで対応できるようになっています。クレバー。

Pandocの変換動作例

Pandoc-crossrefによる相互参照

「Pandocは一度入力ファイルをAST形式に変換している」と説明しましたが、このAST形式のドキュメントに手を加えることで変換処理をカスタマイズできるフィルターという仕組みが存在します。(以下 https://github.com/jgm/pandoc/blob/master/README.md より引用)

Users can also run custom pandoc filters to modify the intermediate AST (see the documentation for filters and Lua filters).

具体的には下図に示すように、AST形式の文書を入力として受け取り、AST形式の文書を出力するプログラムを途中に挟むことで変換処理のカスタマイズを実現しています。こうすることで、入力形式に依存しないカスタマイズと、カスタマイズの容易化を実現しています。スマート。

フィルターの仕組み

フィルターに関する詳細は https://pandoc.org/filters.html をご覧ください。

今回はPandocのフィルターの1つであるpandoc-crossrefというフィルターを用いて文書内での相互参照ができるようにします。相互参照とは、「図1にPandocの変換動作例を示す。」の「図1」のように、図や表、数式、コードブロックの参照番号を自動でつけてくれる機能です。手入力で「図Xに~~を示す。」などと記述してしまうと、編集過程で図やページ順番が変わってしまった場合にいちいち直さなくてはなりません。 では\label{}ref{}を用いることで相互参照が可能ですが、通常のMarkdown形式に相互参照機能は無いためpandoc-crossrefを用いた相互参照を行います。

texファイルからLatexmkを使ってPDFを作成する

次にPandocで作成したtexファイルから、Latexmkを利用してPDFを生成します。そもそもtexファイルからPDFを作成するには、基本的に以下の手順を踏むことになります。

  1. texファイルからdviファイルを作成する
  2. dviファイルからPDFファイルを作成する

手順1で生成するdviファイルには文書のレイアウトに関する情報が記録されており、これをもとに手順2で組版を行います。手順1を行うためにpLaTeXやupLaTeXというエンジンを、手順2を行うためにdvipdfmxなどのソフトを用います。texファイルから直接PDFファイルを生成するpdfLaTeX、XeLaTeX、LuaLaTeX等も存在します。どの処理系を使うかは好みの問題になりますが、私は手順1にupLaTeXを、手順2にdvipdfmxを使用しています[2]

と、ここでは最大2回の操作でPDFが完成するかのように書いていますが、実際はこの操作を何度か繰り返さないと相互参照が正しく表示されません。これらの操作をいちいち手動で繰り返すのは面倒なので、Latexmkで自動化します。Latexmkは、上に述べたPDF作成までに必要な操作を必要回数自動で行ってくれるツールです。Latexmkについてはこちらのサイトでより詳しく紹介されています↓

Latexmkから学ぶPDF化までの処理の流れ - Qiita
texファイルをpdf化するために,TeXShopやW32TeX,latexmk等を使って,ネット上で書かれている設定を何も考えずに動かせば,簡単にpdf化できます. しかし何事も,処理の基本的な流れを理解せずにブラックボックス化...

Pythonで表紙PDFと結合

表紙PDFが指定されている場合は表紙PDFの結合も行います。ウェブアプリの利用などでも出来ますが、PythonのライブラリPyPDF2を使ってサクッと出来たのでこれも自動化しています。参考:Python, PyPDF2でPDFを結合・分割(ファイル全体・個別ページ)https://github.com/mstamy2/PyPDF2

3 方法

以下に具体的な環境構築・レポート作成手順を示します。(https://github.com/detteiu8383/Markdown2PDFから引っ張ってきていい感じにカスタマイズしてもらえると嬉しい)

各種インストール

Markdown

Markdownファイルの作成に特別な準備はほとんど必要ありません。一般的なテキストエディタにはMarkdownのプレビュー機能やショートカットがあることが多いです。私はVSCodeかTyporaで書いています。TyporaはMarkdown専用のエディタで、リアルタイムのプレビュー機能が便利なのでよく使っています。Typoraの特徴やインストールは公式サイトを参照してください。

Pandocのインストール

PandocのインストールはPandocの比較的簡単なインストール方法で詳しく説明されているので紹介させていただきます。基本的にはhttps://github.com/jgm/pandoc/blob/master/INSTALL.mdに示されている手順に従えば大丈夫です。

pandoc-crossrefのインストール

こちらも基本的にはhttps://github.com/lierdakil/pandoc-crossref#installationに示されている手順に従えばOKです。リリースページからダウンロードし、パスが通っている所に配置します。

TeXLive(uplatex,dvipdfmx,biber,Latexmk)のインストール

LaTeXの環境構築はTeXLiveで行うのが多分楽だと思います。詳しくはTeX Wikiのhttps://texwiki.texjp.org/?TeX Liveで説明されているのでこちらを参照してください。

実際の手順

ディレクトリ構造

実際に作成するファイルは以下のようにしています。

./
│  .latexmkrc   <- Latexmkの設定ファイル
│  build.bat    <- コマンドの自動化
│
├─dest
│      output.pdf <- 生成されるPDF
│
└─src
    │  cover.pdf         <- 表紙PDF
    │  references.bib    <- 文献情報
    │  report.md         <- レポート本文のMarkdown
    │
    ├─img
    │      pandoc_description.png <- レポートに挿入する画像
    │      ...
    │
    └─templates
            config.yml    <- Pandocの設定ファイル
            merger.py     <- 表紙PDFが指定されている場合、これでPDFの結合をする
            template.tex  <- テンプレートのtexファイル

Markdownでレポート本文を書く

残念ながらこの手順は手動です。頑張ってください。今回例として作成したMarkdownファイルはhttps://github.com/detteiu8383/Markdown2PDF/blob/master/src/report.mdにあります。これをreport.mdとして保存。

BibTeXで文献情報をまとめる

文献データを作成します。フォーマットについてはhttps://ja.wikipedia.org/wiki/BibTeXで詳しく紹介されています。以下具体例。

@book{
  Laala,
  author="プリパラ制作委員会",
  title="プリパラ&アイドルタイムプリパラ設定資料集<上> <プリズムボイス編+ドリームパレード編>",
  publisher="小学館",
  year="2019",
  pages="96--97"
}

このように、著者名やタイトルをまとめたreferences.bibを作り、本文内で

真中らぁらのキャラクターデザインがほぼ決定したのは2013年7月のことであり、制作初期段階では"ことり"と名づけられていた\cite{Laala}

と書くと、以下のようにコンパイルされます。

コンパイル後

最後に書いた\cite{Laala}が"[1]"に書き変わっていますね。さらに参考文献欄に自動的に整形された書誌情報が記載されます。\cite{} のコマンドですが、Markdown内で のコマンドを使用した場合もちゃんと のコマンドとして処理してくれます。

メタデータの記述

Pandocでの変換に関する設定ファイルを作成します。図表を相互参照したとき、デフォルトでは "fig.1" のように参照されてしまうので、これを日本語化するために次のようなファイルconfig.ymlを作成し、コマンド実行時に指定します。

figureTitle: "図"
tableTitle: "表"
listingTitle: "コード"
figPrefix: "図"
eqnPrefix: "式"
tblPrefix: "表"
lstPrefix: "コード"
secPrefix: "セクション"

PandocでMarkdownファイルをtexファイルに変換する

次に上で記述したreport.mdmain.texに変換します。基本的には以下のコマンドを実行することになります。

pandoc --filter pandoc-crossref \
  --top-level-division=section \
  -M "crossrefYaml=.\src\templates\config.yml" \
  .\src\report.md -o .\src\main.tex

1行目:Pandocを使用、フィルターとしてpandoc-crossrefを用いる。
2行目:トップレベルの見出しをsection(節)にする。このほかdefault,chapter,partが使用可能
3行目:メタデータの設定
4行目:report.mdmain.texに変換

これによって生成されるmain.texはドキュメント部分のみ(\LaTeX の\begin{document}の中身部分)なので、プリアンブルを記述したtemplate.tex内でこれをinputします。

私が使用しているtemplate.texhttps://github.com/detteiu8383/Markdown2PDF/blob/master/src/templates/template.texにあるのでご覧ください。

texファイルからLatexmkを使ってPDFを作成する

Latexmkの詳しい使い方は上で紹介させていただいたサイトで説明されているのでそちらをご覧ください。私は以下のような.mklatexrcを作っています。

#!/usr/bin/env perl
$latex = 'uplatex -halt-on-error';
$latex_silent = 'uplatex -halt-on-error -interaction=batchmode';
$biber = 'biber --bblencoding=utf8 -u -U --output_safechars';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex %O -o %D %S';
$max_repeat = 10;
$pdf_mode = 3;

各オプションはhttps://qiita.com/Rumisbern/items/d9de41823aa46d5f05a8#latexmkで詳しく説明されています。このような設定ファイルを作成することで、面倒なコンパイルが

latexmk template.tex

とコマンドを実行するだけで終わります。

Pythonで表紙PDFと結合

PyPDF2をpip install PyPDF2でインストールし、次に示すmerger.pyを作成します。

import sys
import PyPDF2

args = sys.argv

merger = PyPDF2.PdfFileMerger()

for path in args[1:-1]:
    merger.append(path)

merger.write(args[-1])
merger.close()

これで

python merger.py cover.pdf page1.pdf page2.pdf page3.pdf output.pdf

のように実行すれば、1ページ目から順にcover.pdfpage1.pdfpage2.pdfpage3.pdfが結合されたoutput.pdfが生成されます。

バッチファイルにまとめる

以上の操作を次に示すバッチファイルにまとめ、コマンド実行も自動化します。

@echo off
setlocal EnableDelayedExpansion

set PROJECT_DIR=%cd%
mkdir tmp
xcopy /e src tmp
copy .latexmkrc tmp
cd tmp
pandoc --filter pandoc-crossref ^
--top-level-division=section ^
-M "crossrefYaml=templates\config.yml" ^
report.md -o main.tex
move templates\template.tex .\
latexmk template
python .\templates\merger.py cover.pdf template.pdf output.pdf
move output.pdf %PROJECT_DIR%/dest/output.pdf
cd %PROJECT_DIR%
rd /S /Q tmp
endlocal
pause

やっていることとしては、

  1. 作業用にtmpフォルダを作成し、srcフォルダ内のファイルを全部コピー
  2. tmpフォルダ内でコンパイル
  3. 表紙PDFが指定されている場合、merger.pyでPDFの結合を行う 必要なかったらremでコメントアウトするか消す
  4. 生成されたoutput.pdfだけ出力用フォルダのdestに移動して、tmpフォルダは削除

といった感じです。これでdestにできたてほかほかのoutput.pdfが産まれます。

作業の流れをまとめるとこんな感じ

4 結果

以上の手順を用いて実際にMarkdownからPDFに変換したファイルがhttps://github.com/detteiu8383/Markdown2PDF/blob/master/dest/output.pdfです。変換元のMarkdownはhttps://github.com/detteiu8383/Markdown2PDF/blob/master/src/report.mdでご確認ください。

Markdownとのコマンドの対応はhttps://github.com/detteiu8383/Markdown2PDF/blob/master/README.md#markdown形式とlatex-コマンドの対応に示しているのでご覧ください。

5 考察

6 感想

真のレポート製造機は私だったというオチ。レポート執筆部分がボトルネックになっているので誰かここも自動化してください。

この記事執筆時も未提出レポートが数件溜まっていて本当は記事とか書いている場合じゃないのですがせっかくのブログリレーなので書かせていただきました。未提出レポートが片付いたらもっと丁寧に書き直します。最後まで読んでくださりありがとうございます。

明日の担当は@temmaさんです。たのしみ~


  1. traQについて詳しく知りたい方はこちらの記事をご覧ください→爆☆誕 traQ-S【新歓ブログリレー2020 54日目】 ↩︎

  2. 実はPandoc単体でもMarkdown形式の文書から内部で勝手にLaTeXを経由してPDFを生成することもできるのですが、これでは少し融通が利かない部分があったりしたので私は一度texファイルを生成してからPDFを作っています。 ↩︎

d_etteiu8383 icon
この記事を書いた人
d_etteiu8383

グラフィック班とゲーム班とSysAd班所属 いろいろ活動しています

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2022年9月26日
競プロしかシラン人間が web アプリ QK Judge を作った話
tqk icon tqk
2022年9月16日
5日でゲームを作った #tararira
Komichi icon Komichi
2023年9月27日
夏のブログリレーは終わらない【駄文】
Komichi icon Komichi
2023年9月13日
ブログリレーを支えるリマインダー
H1rono_K icon H1rono_K
2023年8月21日
名取さなになりたくてOBSと連携する配信画面を作った
d_etteiu8383 icon d_etteiu8383
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記