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

LuaLaTeXでフォントサンプル集を作りたい!

経緯

最近スライドを作成する時にフォントを探して回ったりした。自分がフォントに詳しくないのもあり、デフォルトで入っているフォントに関しては、全く知識がなかった。 フォントビューアーを利用すればいいという話もあるが、現環境がUbuntuで、使い勝手が悪かった。

ついでに、好みの問題で大文字の「W」の中央が交差しているフォントがほしかった。

それなので、とりあえずいろいろなフォントで出力するLuaLaTeXスクリプトを書けないかと試行錯誤した。

インストールされているフォント探し: luaotfload-tool

とりあえずどうやらLuaTeX系で使う、フォントDBツールが存在することがわかった。それがluaotfload-toolである。

こんな感じで使う。

# DBの更新
$ luaotfload-tool --update
# インストールされているフォントの一覧を出す
$ luaotfload-tool --list=*
# インストールされているフォントの一覧を、表示項目を指定して出す
$ luaotfload-tool --list=* --fields=plainname

このコマンド、ドキュメントが不完全に感じられる部分があって、例えば--fieldsオプションに指定できる項目がリストアップされていない。

DBを作ると、kpsewhich --var-value=TEXMFVARで出るディレクトリの、luatex/generic/names/luaotfload-names.lua.gzが作成されると思う。 巨大なファイルなので、見ることはあまりおすすめしないが、途中のmappingsの項目に羅列されているものがそれだと思う。コロン以降は簡単な解説。*1

  • basename : パスなしのファイル名。
  • familyname : フォントファミリー名
  • fontname : フォント名
  • format : ファイルのフォーマット(拡張子)
  • fullname : たぶんフォントファミリー名+サブファミリー名
  • fullpath : 絶対パス付きのフォントファイル名
  • index : 内部のインデックス
  • italicangle
  • location
  • pfmweight
  • plainname : フォントの識別名?
  • psname
  • size
  • subfamily : レギュラーとかボールドとかイタリックとか
  • subfont
  • version : フォントバージョン
  • weight
  • width

後にfontspecを利用してフォント変更を行うけど、この時におそらく使えるのはbasenameとplainnameあたり(結論から言って成功はしていない)。その他は未検証。

さて前述のコマンドでフォント一覧が取得できることがわかったので、これを\directluaブロックで取得して適当にループ回せばできるのではって感じで見通しを立てた。

# インストールされているフォントのplainname一覧を出す
$ luaotfload-tool --list=* --fields=plainname

\directluaブロックからの外部コマンド実行

参考に、luaのコードから外部コマンド(例ではls -al)を実行し、出力を得る場合は、次のようにする。

local handle = io.popen("ls -al")
for line in handle.lines() do
    -- ここでなにか色々する。lineには1行分が入っている。
    print(line)
end
handle::close()

上記を参考に\directluaブロックにluaotfload-tool呼び出しを記述しコンパイルすると、エラーが出る。具体的にはpopen()できない。なので、lualatex実行時に、オプション--shell-escapeを付加する必要がある*2

コンパイルの全容を以下に示す。

# main.texをコンパイルする。
$ lualatex --shell-escape main

これで、全ての利用可能(?)なフォントが画面に出力されるはずである。 このときのtexファイルの全容は以下の通り。

% filename: main.tex
\documentclass{ltjsarticle}

\usepackage{luatexja-fontspec}

\begin{document}
test

\directlua{
    local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    print("###################")
    for line in h:lines() do
        print(line)
    end
    print("###################")
    h:close()
}

\end{document}

ここまでは上々。うまく動く。

このままとりあえずフォント名をPDF出力……できない!

なにかよくない文字が含まれているらしい? 本文中で以下のようにするとエラーが出る(再チェック前)。

\directlua{
    fontlist = {}
    local h = io.popen("luaotfload-tool --list=* --fields=plainname | grep -e Han")
    for line in h:lines() do
        tex.print(line)
        tex.print("")
    end
    h:close()
}

\verb||で囲もう。

     %tex.print(line) %%下のように変更
        tex.print("font: \string\\verb|" .. line .. "|")

できた。フォント名がすごいいっぱい並ぶ。 Ubuntuだと1500ぐらい並ぶんじゃないかな?

目的であるフォントを変更して出力

というわけで、このフォント名で\fontspec{}していけばOKなはず!

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%% !!!!!!! 注意: これを動かすべきではない
%% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{ltjsarticle}

\usepackage{luatexja-fontspec}

\newcommand{\sampletext}{ABCDEFGHIJKLMNOPQRSTUVWXYZ

abcdefghijklmnopqrstuvwxyz
}

\begin{document}

\directlua{
    fontlist = {}
    local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    print("###################")
    for line in h:lines() do
        table.insert(fontlist, line)
        tex.print("font: \string\\verb|" .. line .. "|")
        tex.print("")
        tex.print("{\string\\fontspec{" .. line .. "}\string\\jfontspec{" .. line .. "} \string\\sampletext }")
        tex.print("")
    end
    print("###################")
    h:close()
}
\end{document}

これが、うまくいかなかった。利用できないフォントのエラーを無視していったが、その他にもエラーが出て止まった。

エラーの解析

コンパイル時にシステムモニタ(タスクマネージャ)等で確認した限り、メモリをかなり消費している。 具体的には、4GBのメインメモリと4GBのスワップがあったが、(コンパイル以外で1GB前後使っているとはいえ)これらを全て食いつぶしていた。まずい。

というわけで、手元にSource Han Sans一式(7つ)があったので、これらだけでどの程度メモリを食うのか検証した。 そのために、以下のような変更を施した。 厳密さは必要ないので、システムモニタを目視することによる検証をした。

 %local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    local h = io.popen("luaotfload-tool --list=* --fields=plainname | grep Han")

結果、2GB程度のメモリを消費していた。このフォントのサイズが大きいとはいえ、さすがに食い過ぎであるように思うが現実は受け止めなければならない。 この結果を見る限り、1ファイルで全てを出力することは現実的ではないと判断した。

どうするか?→フォント毎にファイルを作ってとり込もう!

とりあえず、メインのファイルから各フォントサンプルのPDFを作成して、それを取り込めば表示できるよね!っていう考えに至った。

そこでこちらがmain.texとなる。

\documentclass{ltjsarticle}

\usepackage{graphicx}

\begin{document}
\directlua{
    fontlist = {}
    local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    print("###################")
    for line in h:lines() do
        if line \string~= "" then
            table.insert(fontlist, line)
        end
    end
    h:close()
}
\begin{itemize}
\directlua{
    for k,v in ipairs(fontlist) do
        local fontname = v
        local filename = v:gsub(" ", "_"):gsub("+", "PLUS")
        local ret = os.execute("lualatex --interaction=nonstopmode --output-directory=outd --jobname=\string\"" .. filename .. "\string\" sample fontname=\string\"" .. fontname .. "\string\"")
        print("##########################", fontname, "::::", filename, "==>>", ret, "#########################")
        tex.print("\string\\item \string\\verb|fontspec{" .. fontname .. "}**|", "\string\\\string\\")
        if ret == 0 then
            tex.print("\string\\includegraphics{outd/" .. filename .. ".pdf}")
        else
            tex.print("!! Error: This compile returns", ret, "!!")
            %tex.print("")
        end
    end
}
\end{itemize}
\end{document}

とりあえず出力が出るか出ないかは気にせず、コンパイルエラーならそれを報告するようにした(エラーコードだけ)が、あまり役に立たなかった。 ファイル名にするための無害化とかTeX出力する上での無害化とかをgsub()で行ったけど、不十分だと思う。+以外の記号が含まれる不フォントもあるんじゃないかな?

また、事前に格納先のフォルダoutdが必要になる。同じフォルダに展開すると視覚的に死ぬので注意。

そして、sample.tex。数式関連は表示していない。

\RequirePackage{luatex85}
\documentclass{standalone}
\usepackage{luatexja}
\usepackage{luatexja-fontspec}
\pagestyle{empty}
\directlua{
    fname = "IPAexMincho"
    for i,v in ipairs(arg) do
        a,b,c = string.find(v, "fontname=(.+)")
        print("###########", a, ":::::", b, ":::::", c, "########")
        if c then
            fname = c
        end
    end
    tex.print("\string\\setmainfont{" .. fname .. "}")
    tex.print("\string\\setmainjfont{" .. fname .. "}")
}
\begin{document}
\begin{tabular}{l}
    abcdefghijklmnopqrstuvwxyz
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    \\
    これは日本語の文書です。
\end{tabular}
\end{document}

standaloneを使うのでluatex85を利用している。フォント指定をコマンドライン引数のインデックスではなく、マッチで行っている。 あまり考えていないので、もしフォント名が渡されなかったらIPAex明朝で表示することにした。

これで動く。ただしコンパイルにすごく時間がかかる。

それと、コンパイルに成功したフォントの数によってはファイルディスクリプタが不足してエラーになることがある。 適当に変更しておこう:うちの環境ではulimit -n 2048でふやせた。

おわりに:今後の更新

気になる部分は指摘していただければと思っています。

  • コメントをつけないとならない。
  • 組み立てを精査しないと少し読みにくい。
  • 環境等を記していない。

以上です、お疲れ様でした。

*1:間違いや追加などのコメントをいただければ幸いです

*2:おそらく、以前pngなどの画像をTeXに取り込む際にはxbbの自動生成の設定が必要だった時のshell escape commandsあたりを弄ればオプションは要らなくなると思うが、私自身はこれ以外の利用ケースを見いだせていないので、コマンドラインオプションとした