GitHub ActionsでAsciiDocをPDF出力しよう(3)
2020-05-15
azblob://2022/11/11/eyecatch/2020-04-22-github-actions-asciidoc-pdf1-0.png

はじめに

前回の「出力編」はPDF出力を行うにあたり、これまで手作業で環境を構築してきた方やリポジトリ内のファイルがどのように準備されるか知りたい方を対象に手順を中心に出力までを説明しました。

今回は「解説編」としてHTML出力からの変更点としてPDF出力の仕組みの理解を深めるとともに、PDF出力の要点を解説したいと思います。

前回までの記事について

これまでの記事はこちらにあります。こちらも合わせてお読みいただけると嬉しいです。

本ページで利用するサンプルについて

出力サンプル用のリポジトリは僕の個人的なプロジェクトの一環で公開しています。
このサンプルではPDF出力でつまづきやすい部分の多くを解決しているので、このサンプルを元にしてご自身の環境を構築すると簡単にPDF出力を行うことができます。
前回の記事とは異なり、今回はこのサンプルの一部を抜粋し解説します。

今回説明するファイルについて

今回利用するファイルやディレクトリの簡単な図は以下の通りです。

シェルスクリプトを書いてPDF出力の指定やりやすくしよう

PDF出力にあたってはasciidoctor-pdfコマンドに対して様々なオプションを指定する必要があります。
サンプルではコマンドとオプションをシェルスクリプトにまとめて記載し、「.github/workflows」配下に「asciidoc.sh」として配置しています。
このファイルで記載している内容の内、重要な部分を見ていきましょう。

※シェルスクリプトを実行するには実行権限が必要です。ファイルをリポジトリからクローンせず自分で作った方は必ずシェルスクリプトに実行権限を付与してPushしてください。

asciidoctor-pdfコマンドで利用するオプションを知ろう

asciidoctor-pdfコマンドを利用するにあたり重要なオプションは以下の通りです。なんとなくでも頭に入れておくと後から出てくるコマンドのオプションが理解しやすいと思います。
また、これらのオプションはPDF出力だけでなくasciidoctor本体のコマンドにも有効です。

  • -a: ドキュメントのアトリビュートを指定します
  • -B: ドキュメントとリソースを含むディレクトリを指定します
  • -D: 出力先のディレクトリを指定します
  • -o: 出力ファイル名を指定します
  • -r: 利用するライブラリを指定します

詳しくは以下のマニュアルに記載があります。

シェルスクリプト内で取得しているパス

シェルスクリプトではよく利用する以下の二つのパスをAsciidoctorを実行するコンテナ環境から取得しています。

CURRENT_PATH=`pwd`
ASCIIDOCTOR_PDF_DIR=`gem contents asciidoctor-pdf --show-install-dir`

まず一つ目の『CURRENT_PATH=pwd』の「pwd」はDockerで現在の作業ディレクトリを取得するコマンド(pwdはPrint Working Directoryの略)です。
こちらがマウントしたファイルの置き場でもあり、リポジトリからチェックアウトしたファイルが入っています。

2つ目の『ASCIIDOCTOR_PDF_DIR=gem contents asciidoctor-pdf --show-install-dir』の「gem contents asciidoctor-pdf --show-install-dir」はGemでasciidoctor-pdfをインストールしたディレクトリを表示するコマンドです。このディレクトリ配下にデフォルトテーマファイルのあるディレクトリ等が配置されています。

これらのパスを毎回Asciidoctorを実行するコンテナ環境から取得することで、環境依存のパスを決め打ちにすることなく正しいパスをオプションとして指定できています。

workflowでシェルスクリプトを呼び出そう

作成したシェルスクリプトをDockerコンテナで実行するためには、「.github/workflows」配下の「asciidoc.yml」で定義しているワークフローの変更が必要です。以下の部分でシェルスクリプトを呼び出します。

# Output command using asciidoctor-action
- name: Build AsciiDoc step
  id: documents
  uses: Analog-inc/asciidoctor-action@v1
  with:
    shellcommand: "./.github/workflows/asciidoc.sh"

日本語フォントの準備と設定をしよう

Asciidoctor-PDFではテーマファイルによって出力後のPDFの見栄えを管理(HTMLでのCSS的な役割を)しており、PDFで表示する文字についてもテーマファイルで指定されてフォントをPDFに埋め込んでいます。
また、テーマファイルで指定するフォントはAsciidoctorを実行するコンテナ環境に配置する必要があります。

Asciidoctor-PDFではPDF出力に必要なフォントやデフォルトテーマがあらかじめ準備されていますが、日本語を綺麗なスタイルで出力する対応はありません。(日本語フォントが広範囲すぎるため以前のバージョンで削除されました。)
このため日本語を綺麗に出力するためにはPDF出力に必要な日本語フォントを準備し、フォントを利用するためのテーマファイルを作成し出力時に読み込む必要があります。

利用するフォント(.ttfファイル)は必ず全てを同じディレクトリに集めよう

テーマファイルでは『pdf-fontsdir』で指定したフォントディレクトリ配下のフォントファイルのみ指定できます。
サンプルでは「fonts」配下に必要なフォントをいくつか配置しています。
なお、フォントはTrueTypeフォント(.ttf形式)のみ利用することができます。

※テーマを継承した場合上位のテーマで利用しているフォントも含めて全て同じディレクトリ配下に集める必要があります。

テーマファイルでのフォントファミリー指定は網羅的に行おう

自分が利用するフォントファミリーをそれぞれ明朝体とゴシック体に分けて定義します。日本語のフォントにitalicはありませんが、フォントの太さで識別できるようにitalic指定を含めた4種類全てに準備したフォントで指定します。

標準的なフォントには明朝体のように文字の端に飾りのある「Serif」とゴシック体のように文字の端に飾りのない「Sans Serif」があります。この二つの標準的な指定も自分が利用するフォントファミリー指定と同じ指定で行います。

さらにAsciidoctor-PDFのデフォルトテーマはSerifとして「Noto Serif」ファミリーを、Sans Serifには「M+ 1mn」ファミリーが指定されています。この二つの定義を改めて自分が利用するフォントファミリー指定と同じ内容で上書きます。この二つのファミリーを上書くことで利用しない英語のフォントをフォントディレクトリに用意する必要がなくなります。

最後に絵文字の対応です。こちらは絵文字フォントとして「Noto Emoji」を指定しています。この絵文字を利用するためにfallbacksの指定を行います。
fallbacksはフォントファイル内に記述すべき文字が見つからない場合に代替で利用するフォントファミリーを指定する機能です。
注意する点として、絵文字のフォントは日本語フォントとサイズが異なる場合が多いため、まず日本語のゴシック体を先に検索しそこで該当しない場合のみ、絵文字フォントから文字を探すように指定します。

サンプルでは「themas」配下に「sample-theme.yml」としてフォントの指定を行っています。

font:
  catalog:
    GenYoMin:
      normal: GenYoMinJP/GenYoMinJP-Regular.ttf
      bold: GenYoMinJP/GenYoMinJP-Bold.ttf
      italic: GenYoMinJP/GenYoMinJP-Light.ttf
      bold_italic: GenYoMinJP/GenYoMinJP-SemiBold.ttf
    GenShinGothic:
      normal: GenShinGothic/GenShinGothic-P-Regular.ttf
      bold: GenShinGothic/GenShinGothic-P-Bold.ttf
      italic: GenShinGothic/GenShinGothic-P-ExtraLight.ttf
      bold_italic: GenShinGothic/GenShinGothic-P-Medium.ttf
    Serif:
      normal: GenYoMinJP/GenYoMinJP-Regular.ttf
      bold: GenYoMinJP/GenYoMinJP-Bold.ttf
      italic: GenYoMinJP/GenYoMinJP-Light.ttf
      bold_italic: GenYoMinJP/GenYoMinJP-SemiBold.ttf
    Sans Serif:
      normal: GenShinGothic/GenShinGothic-P-Regular.ttf
      bold: GenShinGothic/GenShinGothic-P-Bold.ttf
      italic: GenShinGothic/GenShinGothic-P-ExtraLight.ttf
      bold_italic: GenShinGothic/GenShinGothic-P-Medium.ttf
    Noto Serif:
      normal: GenYoMinJP/GenYoMinJP-Regular.ttf
      bold: GenYoMinJP/GenYoMinJP-Bold.ttf
      italic: GenYoMinJP/GenYoMinJP-Light.ttf
      bold_italic: GenYoMinJP/GenYoMinJP-SemiBold.ttf
    M+ 1mn:
      normal: GenShinGothic/GenShinGothic-P-Regular.ttf
      bold: GenShinGothic/GenShinGothic-P-Bold.ttf
      italic: GenShinGothic/GenShinGothic-P-ExtraLight.ttf
      bold_italic: GenShinGothic/GenShinGothic-P-Medium.ttf
    Noto Emoji:
      normal: NotoEmoji/NotoEmoji-Regular.ttf
      bold: NotoEmoji/NotoEmoji-Regular.ttf
      italic: NotoEmoji/NotoEmoji-Regular.ttf
      bold_italic: NotoEmoji/NotoEmoji-Regular.ttf
  fallbacks: [GenShinGothic, Noto Emoji]

テーマファイル作成は上位のテーマを継承して楽をしよう

デフォルトテーマにある全てのスタイルを記載するのは面倒なため、テーマファイルの最初に継承するテーマファイルを記載して内容を省略することができます。

extends: default

この定義はアトリビュート『pdf-styledir』で指定したテーマの配置先内にある、「default-theme.yml」を指定しています。
指定には「-theme.yml」は記載しません。
サンプルの「themas」配下にある「sample-theme.yml」の1行目が継承の指定になります。

テーマファイルで本文やヘッダーのフォントを指定しよう

テーマファイルではどの部分でどのフォントを利用するかを細かく設定することができます。ここでは上記で指定したフォントファミリーで本文やヘッダーのフォントを指定します。

base:
  align: left
  font_color: 222222
  font_family: GenYoMin
  line_height_length: 15

heading:
  font_color: ba3925
  font_family: GenShinGothic
  # h1 is used for part titles (book doctype only)
  h1_font_size: floor($base_font_size * 2.4)
  h2_font_size: floor($base_font_size * 2.4)
  h3_font_size: round($base_font_size * 1.7)
  h4_font_size: round($base_font_size * 1.4)
  h5_font_size: $base_font_size
  h6_font_size: $base_font_size_small
  line_height: 1.4
  margin_top: $vertical_rhythm * 0.9
  margin_bottom: $vertical_rhythm * 0.9

テーマはフォントの指定以外にも様々な指定をCSSのように行うことができます。
詳しくは以下のリンクを参照してください。

テーマやフォントディレクトリの指定はコマンドのオプションに記述しよう

テーマやフォントを配置したディレクトリの指定は『asciidoctor-pdf』コマンドのオプションとしてアトリビュートを指定します。
指定方法は『-a {アトリビュート名}={値}』です。

コマンドのオプションとして指定することで、Asciidoctor-PDFのデフォルトテーマの配置先をテーマの配置先『pdf-styledir』として指定しつつ、リポジトリ内にある自分で作成したテーマファイルを『pdf-style』で指定し継承関係を維持することが可能にしています。またテーマを指定する際はフォントの配置先『pdf-fontsdir』も一緒に指定しましょう。
サンプルでは「.github/workflows」配下にある「asciidoc.sh」のPDF出力部分に記載があります。

# Output PDF
asciidoctor-pdf -B ${CURRENT_PATH}/ -D ${CURRENT_PATH}/outputs/pdf/ -o sample.pdf  -r asciidoctor-diagram -a imagesoutdir=${CURRENT_PATH}/images -r ${CURRENT_PATH}/configs/config.rb -a pdf-styledir=${ASCIIDOCTOR_PDF_DIR}/data/themes -a pdf-style=${CURRENT_PATH}/themes/sample-theme.yml -a pdf-fontsdir=${CURRENT_PATH}/fonts -a scripts=cjk -a allow-uri-read index.adoc

※サンプルでは前回の記事とは異なり「-r asciidoctor-diagram -a imagesoutdir=${CURRENT_PATH}/images -r ${CURRENT_PATH}/configs/config.rb」が入っています。これらのオプションは今回までにまだ利用していないダイアグラム出力に必要なオプションとなります。

外部画像の埋め込みに気をつけよう

PDF出力時に画像の埋め込みを行う際、画像がインターネット上に配置されている場合は注意が必要です。
インターネット上の画像を利用して出力する場合は必ずシェルスクリプトで「asciidoctor-pdf」コマンドのオプションにURI指定による画像の埋め込み許可が必要になります。
サンプルではGitHub Actionsのステータスバッチ表示に利用しています。

-a allow-uri-read

日本語特有のレイアウト崩れや禁則処理を対策しよう

Asciidoctor-PDFはラテン文字と非ラテン文字が混在する場面でレイアウト崩れが起こってしまうことがあります。また日本語には日本語に合わせた禁則処理が必要です。
レイアウト崩れや句読点程度の禁則事項は標準のアトリビュートで防げるので「asciidoctor-pdf」コマンドのオプションを忘れず指定しましょう。

禁則処理(きんそくしょり):「句読点・疑問符・括弧類などの記号が行頭・行末などにあってはならない」などとされる禁止事項を回避するために、字詰めや文の長さを調整する処理

Asciidoctor-PDFでは以下のアトリビュートを指定すると日本語ドキュメントのレイアウトをそれらしく出力することができます。

 -a scripts=cjk 

※ cjkはChinese, Japanese, Koreanの非ラテン文字の頭文字から来ています。これらの言語は似たような処理が必要なため同じスクリプトで対処されています。

まとめ

今回はPDF出力にあたり、ご自身で環境を構築したい方はもちろん、サンプルを利用する場合でもカスタマイズを行いたい場合に必要な内容を解説しましたがいかがでしたでしょうか?
今回の内容に対する公式の解説もありますが英語のドキュメントだったり背景まで中々理解できずつまづきやすい部分かと思います。
次回からはMarkdownからAsciiDocに乗り換えてどんどん利用したくなる便利な機能を紹介させていただきます。