SphinxでPDFを出力するときに、表紙タイトルの折り返し位置を指定する

f:id:aptpod_tech-writer:20201118181120j:plain

弊社では最近、PDF形式のドキュメントを作成するためにSphinxを使っています。1

f:id:aptpod_tech-writer:20200713200005p:plain
Sphinxを使って、reStructuredTextからPDFを作成する

例えば、弊社では先日AWS Marketplaceにてintdash LE All-in-Oneをリリースしましたが、そのドキュメントはSphinxで作成しました。

Sphinxは非常に使いやすいツールですが、本格的に使うようになってから気づいた、使いこなしのコツやノウハウがいくつかあります。

その1つとして今回は、表紙タイトルの折り返しについてご紹介したいと思います。テクニカルライターの篠崎がお届けします。

長い文書タイトルで発生する折り返し

文書のレイアウトを自動化するとき、表紙も自動で作るか、または、別途手作業で作った表紙をあとで結合するか(例えばAdobe Illustratorで1枚のグラフィックとして作るというのがよくある手法でしょうか)は、判断の分かれるところだと思います。

レイアウトを自動化するからには、表紙も自動で作成したいところです。一方、表紙は読者の目に最初に触れるものですから、できるだけ格好よくしたいと考えます。

そこで、バランスのよいレイアウトのテンプレートを作っておいて、決められた位置にテキストや画像を当てはめるのが定番だと思います。

f:id:aptpod_tech-writer:20201118121812p:plain
表紙レイアウトのテンプレート例

それでも、大きな文字で長いタイトルを入れると、行末で折り返しが発生し、見栄えが悪くなることがあります。 英語であれば基本的に単語の区切り(スペース)でしか折り返されませんが、日本語では区切りのスペースを入れませんので、良いところで折り返されるとは限りません。

例として、長いタイトルを持つ文書をSphinxで作ってみます。Sphinxでは、プロジェクト設定ファイルconf.pyの変数projectの値がPDFの表紙タイトルになります。以下のようにしてみました。

# 最小限の設定をしたconf.py

project = 'とても長いタイトルを持ち秋の夜に世界の片隅で作成されたPDF出力テストのためのドキュメント'
author = 'test-author'
language = 'ja'

これでPDFを生成すると以下のようになりました。

f:id:aptpod_tech-writer:20201117231542p:plain
行末で折り返された長いタイトル

あまり格好よくないですね。

Sphinxを使い始めたころは、PDF出力後に編集ツールを使って手作業で改行を入れていたのですが、毎回このような修正をするのは大変です。

f:id:aptpod_tech-writer:20201118122938p:plain
Acrobatで手動で改行を入れる

やはり、自動でレイアウトしているのだから、できるだけ自動化したいですよね。

そこで以下のような方法を採ることにしました。方法はいろいろあると思いますので、一例としてお読みください。

使用した環境は以下の通りです。

  • Windows 10
  • Sphinx v3.3.1
  • TeX Live 2020(pLaTeXとdvipdfmxを使用)

表紙テンプレートをカスタマイズする

適切なレイアウトを実現するため、表紙テンプレートを新しく作ります。そこに、折り返し位置を指定したテキストを埋め込むことにします。2 なお「表紙テンプレート」と呼んでいるものは、実体はLaTeXコマンドです。

以下の(A)~(C)を行います。

  • タイトル内の適切な折り返し位置にLaTeXの改行コマンド \\ を入れておく(A)
  • 表紙テンプレートを再定義する(B)
  • 表紙テンプレート(B)には、改行コマンドが入ったタイトル(A)を挿入する(C)

(準備)表紙のテンプレートを確認する

先まわりして、(B)の表紙テンプレートから考えてみます。

SphinxでPDFを出力する際に使用されるデフォルトの表紙テンプレートは、\sphinxmaketitleというLaTeXコマンドです。 Sphinxソースの中のsphinx/texinputs/sphinxmanual.clsにあります。

\newcommand{\sphinxmaketitle}{%
  \let\sphinxrestorepageanchorsetting\relax
  \ifHy@pageanchor\def\sphinxrestorepageanchorsetting{\Hy@pageanchortrue}\fi
  \hypersetup{pageanchor=false}% avoid duplicate destination warnings
  \begin{titlepage}%
    \let\footnotesize\small
    \let\footnoterule\relax
    \noindent\rule{\textwidth}{1pt}\par
      \begingroup % for PDF information dictionary
       \def\endgraf{ }\def\and{\& }%
       \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup
       \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}%
      \endgroup
    \begin{flushright}%
      \sphinxlogo
      \py@HeaderFamily
      {\Huge \@title \par} % <--- ここで、タイトル\@titleが出力されています
      ...
    \end{flushright}%\par
    ...
  \end{titlepage}%
  ...
}

タイトルの文字列は最終的に\@titleコマンドにバインドされ、このテンプレートを使って出力されることが分かります。

表紙テンプレートを再定義し、改行コマンドの入ったテキストを挿入する

そこで、デフォルトのテンプレートに少しだけ変更を加えて、改行コマンドの入ったタイトルを出力できるようにします。

Sphinxのたくさんのパラメーターの1つlatex_elementspreambleに文字列を設定すると、その文字列はLaTeXファイルのプリアンブルに書き出されます。この仕組みを利用して、テンプレートを再定義(\renewcommand)します(B)。詳細についてはこの下のコード例をご覧ください。

また、タイトルには折り返し位置を指定するための改行コマンドを入れます(A)。設定ファイルconf.pyはPythonコードであるため、設定ファイル内で文字列操作も行うことができます。これを表紙テンプレートに挿入します(C)

# タイトルの折り返し位置を指定したconf.py

author = 'test-author' # 変更なし
language = 'ja' # 変更なし

# タイトルは分割された状態で用意
document_title_lines = [
    'とても長いタイトルを持ち',
    '秋の夜に世界の片隅で作成された',
    'PDF出力テストのためのドキュメント'
]

# 改行コマンド `\\` を挟んで連結する(A)
# バックスラッシュが4つなのは、エスケープのため
my_latex_title_lines = '\\\\'.join(document_title_lines)
# => とても長いタイトルを持ち\\秋の夜に世界の片隅で作成された\\PDF出力テストのためのドキュメント

# LaTeX出力の設定
latex_elements = {
    'preamble': r'''

% my_latex_title_linesをLaTeXの世界に持ち込む
\newcommand{\mylatextitlelines}{''' + my_latex_title_lines + r'''}

% 表紙テンプレート内でアットマークが使われているため、アットマークを通常の文字として扱う
\makeatletter

% 表紙テンプレートを再定義(B)
\renewcommand{\sphinxmaketitle}{%
  \let\sphinxrestorepageanchorsetting\relax
  \ifHy@pageanchor\def\sphinxrestorepageanchorsetting{\Hy@pageanchortrue}\fi
  \hypersetup{pageanchor=false}% avoid duplicate destination warnings
  \begin{titlepage}%
    \let\footnotesize\small
    \let\footnoterule\relax
    \noindent\rule{\textwidth}{1pt}\par
      \begingroup % for PDF information dictionary
       \def\endgraf{ }\def\and{\& }%
       \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup
       \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}%
      \endgroup
    \begin{flushright}%
      \sphinxlogo
      \py@HeaderFamily
      {\Huge \mylatextitlelines \par} % <--- ここで\mylatextitlelinesを使用(C)
      {\itshape\LARGE \py@release\releaseinfo \par}
      \vfill
      {\LARGE
        \begin{tabular}[t]{c}
          \@author
        \end{tabular}\kern-\tabcolsep
        \par}
      \vfill\vfill
      {\large
       \@date \par
       \vfill
       \py@authoraddress \par
      }%
    \end{flushright}%\par
    \@thanks
  \end{titlepage}%
  \setcounter{footnote}{0}%
  \let\thanks\relax\let\maketitle\relax
  %\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
  \clearpage
  \ifdefined\sphinxbackoftitlepage\sphinxbackoftitlepage\fi
  \if@openright\cleardoublepage\else\clearpage\fi
  \sphinxrestorepageanchorsetting
} % 表紙スタイル終わり

% アットマークを特殊文字に戻す
\makeatother
'''
}

# 変数`project`は、各行をそのまま連結したもの
# PDFのメタ情報には正しいタイトルが入る
project = ''.join(document_title_lines)
# => とても長いタイトルを持ち秋の夜に世界の片隅で作成されたPDF出力テストのためのドキュメント

これで、PDFを出力してみます。

f:id:aptpod_tech-writer:20201117231228p:plain
指定どおりに折り返されたタイトル

指定した位置で折り返されています。これで、PDF生成のたびに手作業で折り返し位置を修正する必要はなくなりました。3

新しい表紙テンプレート\sphinxmaketitleは、他のドキュメントにも使いまわしができます。 この説明ではテンプレートをconf.pyに直接書き込みましたが、LaTeXのスタイルファイル(.sty)として分離することで、より使いまわしを楽にすることも可能です。

まとめ―Sphinxの柔軟性

Sphinxは非常に柔軟にカスタマイズできるツールです。柔軟性を高めている特徴として、以下があります:

  • たくさんのパラメーターが変更可能であること(しかも、痒い所に手が届くパラメーターが存在すること)
  • レイアウトのテンプレートがモジュール化されており、それぞれ再定義可能であること
  • 設定ファイルconf.pyがPythonコードであり、ドキュメント生成時に評価されるものであること

今回の例ではこれらの特徴を活用し、パラメーター内で新たにテンプレートを定義しました。また、改行コマンドを挿入するという単純な操作ではありますが、PythonでLaTeXコードの断片を生成しました。Sphinxの持つ柔軟性の一端をご紹介できたかと思います。

今後もうまく使いこなしたいと考えています。


  1. Sphinxを採用した背景や、LuaLaTeXによる日本語PDFの作成方法については、以前のエントリーSphinxとLuaLaTeXで、日本語PDFマニュアルを作る - aptpod Tech Blogにて公開しています。

  2. 折り返し位置を指定するために、変数projectにLaTeXの改行コマンド \\ を挿入し、 project = 'とても長いタイトルを持ち\\\\秋の夜に世界の片隅で作成された\\\\PDF出力テストのためのドキュメント' のようにしてもうまくいきません。Sphinxの処理のなかでバックスラッシュがエスケープされるためです。

  3. この新しい表紙テンプレートのコードは、{}$% のようなLaTeXの特殊文字を最初から含むタイトルには対応していません。