読者です 読者をやめる 読者になる 読者になる

(8日目) Sphinx から PDF を生成してみよう (rst2pdf 編)

今日のアドベントカレンダーでは Sphinx で PDF 出力する方法をご紹介します。

Sphinx から PDF を出力するには 2種類の方法があります。
ひとつは Sphinx 標準で提供されている LaTeX 経由で PDF を出力する方法です。
もうひとつは rst2pdf をインストールし、rst2pdf の Sphinx 拡張機能を用いる方法です。

二通りある PDF 出力について、僕は次のような印象を持っています。*1

  • LaTeX 経由
    • LaTeX による美しい PDF 出力が期待できる
    • TeX のスタイルを書き換えることで、デザインを変えることができそう
    • .tex ファイルから PDF への変換は Sphinx の他に TeXLive (など)が必要
      • TeXLive は巨大パッケージであるため、容量がとても大きい(約 2GB)
    • TeXLive 2010 以降でないと日本語の扱いがいまいち*2
  • rst2pdf 経由
    • rst2pdf のインストールがかんたん(TeXLive と比べると)
    • Sphinx 経由で rst2pdf を利用するとデザインの自由がほとんど無い
    • rst2pdf の作者は Sphinx を利用しておらず、質問に対してシブめの返事が来る
    • 使えない Sphinx 拡張がたまにある

なお、第三勢力の座を sphinxcontrib-docxbuilder が狙っています。
こちらの特徴はこんな感じです。

  • sphinxcontrib-docxbuilder
    • MS-Word の機能を用いて PDF 出力する
    • Word のデザインテンプレートを使うのでデザイン調整がしやすい
    • でもバージョンがまだ 0.0.1alpha 。

今日はこれらのうち、rst2pdf を使った PDF 出力を取り上げてみようと思います。

rst2pdf とは

rst2pdf は Roberto Alsina さんが開発したツールで、reST 形式のテキストから PDF を生成するツールです。
Sphinx は標準の reST に対して独自の拡張(ディレクティブやロールなど)を加えていますが、rst2pdf は標準の reST が対象になります。

本来は rst2pdf は単体で利用するツールですが、PDF 出力部分を Sphinx から利用できるよう Sphinx 拡張を提供しているため、
Sphinx から利用することも出来ます。

rst2pdf を使ってみる

Debian squeeze では rst2pdf パッケージが存在しますが、少しバージョンが古いので easy_install を使います。
依存パッケージである reportlab と PIL はビルドに時間がかかるので、こちらは apt でインストールします。

$ sudo apt-get install python-reportlab pythong-imaging
$ sudo easy_install rst2pdf

次に日本語用の設定ファイルを作成します。
デフォルトでは rst2pdf は日本語が利用できないようになっているので、
フォントの設定をする必要があります。
ja.json というファイル名で以下の内容を保存します。

{
    "fontsAlias" : {
        "stdFont": "VL-PGothic-Regular",
        "stdBold": "VL-PGothic-Regular",
        "stdItalic": "VL-PGothic-Regular",
        "stdBoldItalic": "VL-PGothic-Regular",
        "stdMono": "VL-Gothic-Regular",
        "stdMonoBold": "VL-Gothic-Regular",
        "stdMonoItalic": "VL-Gothic-Regular",
        "stdMonoBoldItalic": "VL-Gothic-Regular",
        "stdSans": "VL-Gothic-Regular",
        "stdSansBold": "VL-Gothic-Regular",
        "stdSansItalic": "VL-Gothic-Regular",
        "stdSansBoldItalic": "VL-Gothic-Regular"
    },
    "styles" : [
        ["base" , {
            "wordWrap": "CJK"
        }],
        ["literal" , {
            "wordWrap": "None"
        }]
     ]
}

それでは試しに rst2pdf を単体で利用してみます。
サンプルとして次のような reST ファイルを用意しました。

=============================
rst2pdf sample documentation
=============================

これは rst2pdf を利用するサンプルです。

blockdiag の紹介
=================

blockdiag シリーズは以下のパッケージから構成されています。

* blockdiag
* seqdiag
* actdiag
* nwdiag
   * nwdiag
   * rackdiag

blockdiag パッケージとコマンド群
=================================

もちろん表も書けます。

============  =========
パッケージ名  コマンド
============  =========
blockdiag     blockdiag
seqdiag       seqdiag
actdag        actdiag
nwdiag        nwdiag
              rackdiag
============  =========

ではこのファイル(blockdiag.rst)を PDF に変換してみます。

$ rst2pdf -s ja blockdiag.rst

生成された PDF (blockdiag.pdf) はこのような表示になります。

Sphinx から使ってみよう

rst2pdf を Sphinx から利用する際はいくつか設定が必要です。

  • conf.py の書き換え
  • Makefile の書き換え
  • ja.json の作成

それぞれについて順番に説明していきます。

conf.py の書き換え

まずは rst2pdf を有効にするため conf.py を編集します。
ここで、かならず pdf_stylesheets の設定を忘れないようにしてください。
rst2pdf 単体と同じように日本語を有効にする設定('ja')が含まれています。

extensions += ['rst2pdf.pdfbuilder']

pdf_documents = [
    ('index', u'MyProject', u'My Project', u'Author Name'),
]

# A comma-separated list of custom stylesheets.
pdf_stylesheets = ['sphinx', 'kerning', 'a4', 'ja']

# Language to be used for hyphenation support
pdf_language = "ja"

また、前述の ja.json を Sphinx プロジェクトのディレクトリにコピーしておきます。

Makefile の書き換え

Makefile には rst2pdf 経由でビルドする make ターゲットが記述されていないので、
Makefile に pdf ターゲットを追加します。

pdf:
    $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) $(BUILDDIR)/pdf
    @echo
    @echo "Build finished. The PDF files are in _build/pdf."

引数なしで make コマンドを実行した時に表示されるヘルプに
pdf がリストアップされないのが気になる人は help ターゲットに

        @echo "  pdf        to make pdf file"

を足しておくとよいかもしれません。

ここまで設定すると make pdf すると Sphinx ドキュメントを PDF 出力することができます。

$ make pdf
bin/sphinx-build -b pdf -d _build/doctrees   . _build/pdf
Running Sphinx v1.1.2
loading translations [ja]... done
loading pickled environment... done
building [pdf]: targets for 1 source files that are out of date
updating environment: 0 added, 1 changed, 1 removed
reading sources... [100%] index

looking for now-outdated files... none found
pickling environment... done
checking consistency... done
processing MyProject... index
resolving references...
done
writing MyProject... done
build succeeded.

Build finished. The PDF files are in _build/pdf.

$ ls _build/pdf
MyProject.pdf


Sphinx 経由で出力すると表紙や目次が付きます。
これらが不要な場合は conf.py の設定で調整することができます。

# 表紙を出力しない
pdf_use_coverpage = False

# 目次を出力しない
pdf_use_toc = False
エラーが出る人へ

rst2pdf と docutils-0.8 以降の組み合わせでは、以下のようなエラーが発生します。

$ make pdf
bin/sphinx-build -b pdf -d _build/doctrees   . _build/pdf
Running Sphinx v1.1.2
loading translations [ja]... done
loading pickled environment... done
building [pdf]: targets for 2 source files that are out of date
updating environment: 0 added, 0 changed, 0 removed
looking for now-outdated files... none found
processing MyProject... index [ERROR] pdfbuilder.py:129 get_language() takes exactly 2 arguments (1 given)
Traceback (most recent call last):
  File "/home/katsuwo/.buildout/buildout-eggs/rst2pdf-0.16-py2.6.egg/rst2pdf/pdfbuilder.py", line 121, in write
    appendices=opts.get('pdf_appendices', self.config.pdf_appendices) or [])
  File "/home/katsuwo/.buildout/buildout-eggs/rst2pdf-0.16-py2.6.egg/rst2pdf/pdfbuilder.py", line 188, in assemble_doctree
    self.docutils_languages[lang] = get_language(lang)
TypeError: get_language() takes exactly 2 arguments (1 given)
FAILED
build succeeded.

この問題に対する修正が提供されているので、docutils に回避用のパッチを適用するとよいでしょう。


さて、今日は rst2pdf を使って PDF 出力する方法をご紹介しました。
標準で利用できる HTML や ePub とあわせて、よく利用する方法だと思います。
ぜひ利用してみてください。

*1:個人の感想です。

*2:Debian には texlive 2009 がパッケージングされているので、UTF8 がうまく扱えません