org-modeのBeamerクラスのフレームの縦位置を中間ではなく上に固定する

経緯

org-modeのBeamerクラスの欠点

先の記事 でorg-modeのBeamerクラスでスライドを作成するための設定を行いましたが、実は不満が残っていました。それは

  • フレームの縦位置が中央にきてしまう

ことでした。

サンプルファイルとして

#+TITLE: Sample
#+AUTHOR: Toshiaki Ara
#+OPTIONS: H:1 toc:nil
#+LATEX_CLASS: beamer
#+BEAMER_THEME: Madrid

* Frame
** block
+ contents 1
+ contents 2

を用意し、PDFファイルに変換するとこのような感じになります。

test_nul.png

これではスライドを進めていくたびにフレームの始まる位置が異なるため、見る方としては非常につらいです(個人の感想です)。

これを何とか上に固定したいと思い、 ox-beamer のソースコードを調べました。

結論

init.elに

(setq org-beamer-frame-default-options "t")

を追加することでフレームの縦位置が上に固定されるようになりました。

test_t.png

ただし、これでは各ファイルごとの設定ができません。 orgファイルのオプションで設定できる方法があればいいのですが。

それでも、 org-modeによる簡単な記述でこれほど見栄えのよいスライドが作成できるので、積極的に使用したいと思います。 org-modeは見出しレベルで折り畳みできるのが気に入ってます。

ox-beamer.elの解析

先に結論だけを書いたので、次にこの結論に至った経緯を簡単に書きます。

org-beamer–format-frame関数の発見

まずox-beamer.elの中でフレームを定義している関数を探しました。するとすぐにorg-beamer–format-frameが見つかりました。

少し長いですが、ox-beamer.elに書かれている org-beamer–format-frameの関数定義を下に示します。

見やすくするためにタブを空白に変換し、さらに C-M-q でコードを整形しています。

すると26行目に

(org-split-string org-beamer-frame-default-options ",")

という記述がありました。これは org-beamer-frame-default-options という変数に含まれているリストを,で区切った文字列として返す関数であると予想しました。

M-: org-beamer-frame-default-options

で変数の中身を調べると””でした(何も定義されていない)。

そこでフレームを上に固定するためのオプションである”t”を設定したところ希望通りの結果が得られました。

org-beamer–format-frameの関数定義

(defun org-beamer--format-frame (headline contents info)
  "Format HEADLINE as a frame.
CONTENTS holds the contents of the headline.  INFO is a plist
used as a communication channel."
  (let ((fragilep
         ;; FRAGILEP is non-nil when HEADLINE contains an element
         ;; among `org-beamer-verbatim-elements'.
         (org-element-map headline org-beamer-verbatim-elements 'identity
                          info 'first-match)))
    (concat "\\begin{frame}"
            ;; Overlay specification, if any. When surrounded by
            ;; square brackets, consider it as a default
            ;; specification.
            (let ((action (org-element-property :BEAMER_ACT headline)))
              (cond
               ((not action) "")
               ((string-match "\\`\\[.*\\]\\'" action )
                (org-beamer--normalize-argument action 'defaction))
               (t (org-beamer--normalize-argument action 'action))))
            ;; Options, if any.
            (let* ((beamer-opt (org-element-property :BEAMER_OPT headline))
                   (options
                    ;; Collect options from default value and headline's
                    ;; properties.  Also add a label for links.
                    (append
                     (org-split-string org-beamer-frame-default-options ",") ;; <= ココ
                     (and beamer-opt
                          (org-split-string
                           ;; Remove square brackets if user provided
                           ;; them.
                           (and (string-match "^\\[?\\(.*\\)\\]?$" beamer-opt)
                                (match-string 1 beamer-opt))
                           ","))
                     ;; Provide an automatic label for the frame
                     ;; unless the user specified one.
                     (unless (and beamer-opt
                                  (string-match "\\(^\\|,\\)label=" beamer-opt))
                       (list
                        (format "label=%s"
                                (org-beamer--get-label headline info)))))))
              ;; Change options list into a string.
              (org-beamer--normalize-argument
               (mapconcat
                'identity
                (if (or (not fragilep) (member "fragile" options)) options
                  (cons "fragile" options))
                ",")
               'option))
            ;; Title.
            (let ((env (org-element-property :BEAMER_ENV headline)))
              (format "{%s}"
                      (if (and env (equal (downcase env) "fullframe")) ""
                        (org-export-data
                         (org-element-property :title headline) info))))
            "\n"
            ;; The following workaround is required in fragile frames
            ;; as Beamer will append "\par" to the beginning of the
            ;; contents.  So we need to make sure the command is
            ;; separated from the contents by at least one space.  If
            ;; it isn't, it will create "\parfirst-word" command and
            ;; remove the first word from the contents in the PDF
            ;; output.
            (if (not fragilep) contents
              (replace-regexp-in-string "\\`\n*" "\\& " (or contents "")))
            "\\end{frame}")))

このコードはGNU Emacsの一部であるため GNU General Public Licenseが適用されています。

org-modeのBeamerクラスでlualatexを使用してPDFファイルを作成する

経緯

全てではありませんが、講義用のスライドをLaTeXのBeamerクラスで作成しています。

以前は platex -> dvipdfmx の順でPDFファイルを作成していましたが、現在は lualatex を使用して直接PDFファイルを作成しています。

  • 利点
    • PDF形式の図を直接挿入できる
    • フォントの扱いが楽(個人的な感想)

今までは使用していませんでしたが Emacsのorg-modeからBeamerクラスの形式で出力できるため、 lualatexを使用してPDFファイルを作成できるように設定しました。その時のメモです。

うまくいきそうなので今後はorg-modeで原稿を作成していきたいと思いました。

ちなみに Beamerクラスだけではなく通常のltjsarticleでも可能でした。

init.elに追加する設定

Beamer用

LaTeXで使用するクラスファイルおよびパッケージ

Beamerクラスを使用するための個人的設定です。デフォルトの設定ではもっと多くのパッケージを使用しているため個人的に必要だと思うものだけを含めています。

この中でlualatexを使用する上で必須なのは

です。これがないと日本語が使用できません。プロジェクトの皆様には感謝でいっぱいです。

%%Fontsは個人の好みです。

  • 数式フォント:TeX Gyre Termes(Times系)
  • セリフ体:TeX Gyre Termes
  • サンセリフ体:TeX Gyre Heros(Helvetica系)
  • 日本語:IPAexゴシック

を使用するように設定しています。

(require 'ox-beamer)

(add-to-list 'org-latex-classes
             '("beamer"
               "\\documentclass[presentation]{beamer}
[NO-DEFAULT-PACKAGES]
\\usepackage{luatexja}
\\usepackage{textcomp}
\\usepackage{graphicx}
% \\usepackage{booktabs}
\\usepackage{longtable}
\\usepackage{wrapfig}
\\usepackage{hyperref}
\\hypersetup{pdfencoding=auto, linkbordercolor={0 1 0}}
%% Fonts
% mathematical font
\\usepackage{fontspec}
\\usepackage{amsmath, amssymb}
\\usepackage{qtxmath}    % Times (Gyre Termes)
% English
\\setmainfont[BoldFont=TeXGyreHeros, Ligatures=TeX]{TeXGyreTermes}  %Times
\\setsansfont[Ligatures=TeX]{TeXGyreHeros}                          % Helvetica
% Japanese
\\usepackage{luacode}
\\usepackage{luatexja-otf}
\\usepackage[ipaex]{luatexja-preset}
\\renewcommand{\\kanjifamilydefault}{\\gtdefault}
%%
\\setbeamercovered{transparent}
\\setbeamertemplate{navigation symbols}{}"
  ("\\section{%s}" . "\\section*{%s}")
  ("\\subsection{%s}" . "\\subsection*{%s}")
  ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
  ("\\paragraph{%s}" . "\\paragraph*{%s}")
  ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

変換エンジンとしてlualatexを使用するための設定

org-latex-で始まるコマンドを調べたところ org-latex-pdf-process が該当しました。

(setq org-latex-pdf-process
      '("lualatex --draftmode %f"
        "lualatex %f"))

と設定することで lualatexを使用するように変更できました。

lualatexを2回使用している理由は

  • 相互参照
  • ページ数および見出しの確定

です。 lualatexを1回しか使用しない場合には総ページ数が正しく表示されず、見出しも空欄のままでした。 **.tocなどの中間ファイルが必要なのに 自動的に削除するのがその理由のようです。

とりあえずこれで直接PDFファイルに変換できるようになりました。今後微調整が必要かもしれませんがこれで試したいと思います。

ltjsarticle用

スライドではなく通常の書類を作成する場合には ltjsarticleクラスを使用します(むしろこちらの方が頻度が高い)。

LaTeXで使用するクラスファイルおよびパッケージ

以下設定です。

(require 'ox-latex)

(add-to-list 'org-latex-classes
             '("ltjsarticle"
               "\\documentclass[12pt,a4paper]{ltjsarticle}
[NO-DEFAULT-PACKAGES]
\\usepackage{amsmath}
% \\usepackage{newtxtext,newtxmath}
\\usepackage{textcomp}
\\usepackage{graphicx}
\\usepackage{booktabs}
\\usepackage{longtable}
\\usepackage{wrapfig}
\\usepackage{hyperref}
\\hypersetup{pdfencoding=auto}"
  ("\\section{%s}" . "\\section*{%s}")
  ("\\subsection{%s}" . "\\subsection*{%s}")
  ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
  ("\\paragraph{%s}" . "\\paragraph*{%s}")
  ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

デフォルトのドキュメントクラスとしてltjsarticleを使用するための設定

デフォルトではarticleクラスが選択されます。

そこで

(setq org-latex-default-class "ltjsarticle")

とするとltjsarticleがデフォルトで選択されるようになります。

先ほどのorg-latex-pdf-processの設定で lualatexが使用されるようになっています。