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

Windows環境でSphinxを使って日本語PDFを作成するメモ

Python Sphinx

参考URL

前提条件

easy_installで依存ライブラリもインストールされるはず。今回試したのは以下のバージョン。

ディレクトリ構成はこんな感じ

WORK_DIR
  +-build ・・・ 成果物格納ディレクトリ
  +-fonts ・・・ フォント格納ディレクトリ
  +-souce ・・・ ソース格納ディレクトリ
        +- index.rst ・・・ ソース
        +- conf.py
        +- ja.json
  +- make.bat
  +- Makefile

日本語フォント

VLゴシックフォントIPAフォントをダウンロードしてきて、WORK_DIR\Fontsにコピーする。C:\WINDOWS\Fontsディレクトリにインストールしてもいいが、Sphinxの設定はPythonコードなので、フォントパスを指定してあげればどこに配置しても構わないはず。

conf.py修正

参考URLのように修正すればいいが、次の2点は以下のように修正する。

  • pdf_stylesheetsは、sphinxとjaのみ指定する。そうしないと余計なフォントを探しに行って、PDF作成にとても時間がかかる。
  • pdf_font_pathには、先程ダウンロードしてきたフォントのコピー先を指定する。
pdf_stylesheets = ['sphinx','ja']
import os
font_dir = os.path.abspath(os.path.join(os.path.split(__file__)[0], os.pardir, 'fonts'))
pdf_font_path = [font_dir, 'C:\WINDOWS\Fonts']
pdf_language = "ja"

ja.json

これはほぼ参考URLのとおり。ただし、IPAフォントは*.otfではなくて*.ttfなので、そこだけ修正する。

{
  "embeddedFonts" : [
    [
        "VL-Gothic-Regular.ttf",
        "VL-PGothic-Regular.ttf",
        "ipam.ttf",
        "verdanaz.ttf"
     ]
  ],
  "fontsAlias" : {
    "stdFont": "VL-PGothic-Regular",
    "stdBold": "VL-PGothic-Regular",
    "stdItalic": "VL-PGothic-Regular",
    "stdBoldItalic": "VL-PGothic-Regular",
    "stdMono": "VL-PGothic-Regular",
    "stdMonoBold": "VL-PGothic-Regular",
    "stdSanBold": "VL-PGothic-Regular",
    "stdSansBold": "VL-PGothic-Regular"
  },
  "styles" : [
    ["base" , {
      "wordWrap": "CJK",
      "kerning" : true
    }],
    ["literal" , {
      "wordWrap": "None"
    }]
  ]
}

バッチファイル修正

make.batを修正して、"make pdf"でPDFを作成できるようにする。

if "%1" == "pdf" (
	%SPHINXBUILD% -b pdf %ALLSPHINXOPTS% %BUILDDIR%/pdf
	echo.
	echo.Build finished. The PDF files are in %BUILDDIR%/pdf
	goto end
)

これで一応日本語PDFが作成できるんだけども、外部リンクを貼るときターゲット定義とリンクを分割するとエラーが発生する。原因はよくわからない。

目次

詳細は `Sphinx Document`_ を参照してください。

.. _Sphinx Document: http://sphinx-users.jp/doc10/index.html
Running Sphinx v1.0.4
loading translations [ja]... done
loading pickled environment... done
building [pdf]: targets for 1 source files that are out of date
updating environment: 0 added, 0 changed, 0 removed
looking for now-outdated files... none found
processing pythontest... index 
resolving references...
done
writing pythontest... [ERROR] pdfbuilder.py:129 FragLine instance has no attribute 'lineBreak'
FAILED
build succeeded.
Traceback (most recent call last):
  File "D:\Work\pytest\python\lib\site-packages\rst2pdf-0.16-py2.6.egg\rst2pdf\pdfbuilder.py", line 126, in write
    docwriter.write(doctree, destination)
  File "D:\Work\pytest\python\lib\site-packages\docutils-0.7-py2.6.egg\docutils\writers\__init__.py", line 76, in write
    self.translate()
  File "D:\Work\pytest\python\lib\site-packages\rst2pdf-0.16-py2.6.egg\rst2pdf\pdfbuilder.py", line 624, in translate
    compressed=self.compressed)
  File "D:\Work\pytest\python\lib\site-packages\rst2pdf-0.16-py2.6.egg\rst2pdf\createpdf.py", line 666, in createPdf
    pdfdoc.multiBuild(elements)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\doctemplate.py", line 960, in multiBuild
    self.build(tempStory, **buildKwds)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\doctemplate.py", line 880, in build
    self.handle_flowable(flowables)
  File "D:\Work\pytest\python\lib\site-packages\rst2pdf-0.16-py2.6.egg\rst2pdf\createpdf.py", line 774, in handle_flowable
    if frame.add(f, canv, trySplit=self.allowSplitting):
  File "D:\Work\pytest\python\lib\site-packages\rst2pdf-0.16-py2.6.egg\rst2pdf\flowables.py", line 555, in add
    return Frame.add(self, flowable, canv, trySplit)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\frames.py", line 174, in _add
    flowable.drawOn(canv, self._x + self._leftExtraIndent, y, _sW=aW-w)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\flowables.py", line 108, in drawOn
    self._drawOn(canvas)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\flowables.py", line 89, in _drawOn
    self.draw()#this is the bit you overload
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\paragraph.py", line 992, in draw
    self.drawPara(self.debug)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\paragraph.py", line 1458, in drawPara
    dpl( tx, offset, lines[0], noJustifyLast and nLines==1)
  File "D:\Work\pytest\python\lib\site-packages\reportlab-2.5-py2.6-win32.egg\reportlab\platypus\paragraph.py", line 335, in _justifyDrawParaLineX
    simple = last or abs(extraSpace)<=1e-8 or line.lineBreak
AttributeError: FragLine instance has no attribute 'lineBreak'

Build finished. The PDF files are in build/pdf

追記

reportlab.platypus.paragraphモジュールの335行目が原因なので、lineBreak属性がなくても例外が発生しないように無理やり修正したらなんとかPDFが作成できた。ただし、コードブロックの日本語が文字化けする・・・

def _justifyDrawParaLineX( tx, offset, line, last=0):
    setXPos(tx,offset)
    extraSpace = line.extraSpace
    #simple = last or abs(extraSpace)<=1e-8 or line.lineBreak
    simple = last or abs(extraSpace)<=1e-8 or getattr(line, 'lineBreak', False)
    if not simple:
        nSpaces = line.wordCount+sum([_nbspCount(w.text) for w in line.words if not hasattr(w,'cbDefn')])-1
        simple = not nSpaces
    if not simple:
        tx.setWordSpace(extraSpace / float(nSpaces))
        _putFragLine(offset, tx, line)
        tx.setWordSpace(0)
    else:
        _putFragLine(offset, tx, line)  #no space modification
    setXPos(tx,-offset)