マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

dvipdfmxのフォントマップのunicodeの話(1)

この記事では「dvipdfmxの和文用のフォントマップの書き方は何となくわかるけど、CMap指定(2カラム目)をunicodeにする書き方の意味がわからない」という人のために、従来のCMap指定とunicode指定の違いについて、何となく説明する。

※この記事では「CFFグリフのOpenTypeフォント」のことを“OpenTypeフォント”、「TrueTypeグリフのOpenTypeフォント」のことを“TrueTypeフォント”と呼ぶ。

CMap指定の4つのパターン

pTeX・upTeXの標準和文TFM1およびjapanese-otfパッケージの和文TFMのセットに対象を限ることにする。このセットに対するフォントマップのCMap指定として、主に以下に述べる4つのパターンが使われている。

※フォントマップの例は「横組・明朝・中字」のマップ行を抜粋して示す。他のウェイトについても全く同様になる。

OpenTypeフォント+CMap指定

rml         H                   HogeraMincho-Regular.otf
uprml-h     UniJIS-UTF16-H      HogeraMincho-Regular.otf
uprml-hq    UniJIS-UCS2-H       HogeraMincho-Regular.otf
hminr-h     H                   HogeraMincho-Regular.otf
hminrn-h    2004-H              HogeraMincho-Regular.otf
otf-ujmr-h  UniJIS-UTF16-H      HogeraMincho-Regular.otf
otf-ujmrn-h UniJIS2004-UTF16-H  HogeraMincho-Regular.otf
otf-cjmr-h  Identity-H          HogeraMincho-Regular.otf
(標準和文を2004JIS字形にしたい場合は最初の2行を差し替える)
rml         2004-H              HogeraMincho-Regular.otf
uprml-h     UniJIS2004-UTF16-H  HogeraMincho-Regular.otf

指定したCMapの変換先のCIDのグリフが出力される。

uprml-hの0x2603   ―(UniJIS-UTF16-H)→   CID+8218のグリフ
  • 利点
    • 標準和文フォントにおいてJIS X 0208の範囲の文字が全て全角幅で使える。
      • 標準和文TFMは全角幅なので、物理フォント側のグリフが全角幅でないならそれは使えない。
    • japanese-otfの機能が全て使える。
      • つまり、\CID命令により、固定幅のグリフが全て使える。
    • 文字情報(ToUnicodeの結果)が“変な文字”にならない。(“部首文字問題”が起こらない。)
  • 欠点

ある意味、標準和文とjapanese-otfにとって最も理想的な状態といえる。従って、AJ1のOpenTypeフォントの場合はこれを適用すべきである。次節以降の利点欠点比較はAJ1のOpenType以外のフォントを前提とする。

TrueTypeフォント+CMap指定(フォールバック)

rml         H                   HogeraMincho-Regular.ttf
uprml-h     UniJIS-UTF16-H      HogeraMincho-Regular.ttf
uprml-hq    UniJIS-UCS2-H       HogeraMincho-Regular.ttf
hminr-h     H                   HogeraMincho-Regular.ttf
hminrn-h    2004-H              HogeraMincho-Regular.ttf
otf-ujmr-h  UniJIS-UTF16-H      HogeraMincho-Regular.ttf
otf-ujmrn-h UniJIS2004-UTF16-H  HogeraMincho-Regular.ttf
otf-cjmr-h  Identity-H          HogeraMincho-Regular.ttf

CMapの指定は①と全く同じで、ただマップ先の物理フォントがTrueTypeフォントであることが違う。

TrueTypeフォントはAJ1のCIDでアクセスできないので、CMapの変換先のCIDにさらにToUnicodeを適用して結果のUnicode値の(既定の)グリフが出力される。(この場合、2004JIS字形用のCMapを指定しても結果は変わらない。)

uprml-hの0x2603   ―(UniJIS-UTF16-H)→   CID+8218   ―(ToUnicode)→   U+2603のグリフ
  • 利点
    • Unicode以外のTFM(rmlなど)でも対応できる。
    • 古いdvipdfmxでもサポートしている。
    • 文字情報(ToUnicodeの結果)が“変な文字”にならない。
      • 内部的にはAJ1のフォントと同じ扱いになるため、らしい。
  • 欠点
    • Unicode文字に対する既定のグリフしか使えない。
      • 例えば、90JIS字形と2004JIS字形の区別は(物理フォントの側が対応していたとしても)無効になる。
    • このため、標準和文フォントにおいてJIS X 0208の範囲の一部の文字が使えない可能性が生じる。
      • 例えば、最近のフォントではクオートの既定のグリフがプロポーショナル幅になっているので、標準和文としては使えない。たとえそのフォントが全角幅のクオートのグリフを別にもっていたとしても、それは使えない。
    • UnicodeのTFMについて、一度CIDの変換を挟むため、一部のUnicode文字が利用できない、あるいは、入力した文字とは別の文字が出力される場合がある。
      • 例えば、U+22EF は、U+22EF→CID+668→U+2026 と変換される。
      • U+263A(☺)はAJ1にない文字なので使えない。

昔は「AJ1のOpenTypeフォント」と「TrueTypeフォント」しかなかったので、①②のパターンだけ(つまり常に「CMap指定」を行う)で全て済んでいた2。この場合、前者の場合は①、後者の場合は②と解釈されることになる。

Unicode直接指定

%rml は無理
uprml-h     unicode             HogeraMincho-Regular.otf
uprml-hq    unicode             HogeraMincho-Regular.otf
%hminr-h は無理
%hminrn-h は無理
otf-ujmr-h  unicode             HogeraMincho-Regular.otf
otf-ujmrn-h unicode             HogeraMincho-Regular.otf
%otf-cjmr-h は無理
(縦組用TFMについては以下のようにする)
uprml-v     unicode             HogeraMincho-Regular.otf -w 1

CMap指定をunicodeにした場合、TFMの符号値をUnicode値とするグリフを出力する。物理フォントの種類は問わない。

uprml-hの0x2603   ―→   U+2603のグリフ
  • 利点
    • AJ1でないOpenTypeフォントにも適用できる。
    • 必ず入力したUnicodeの文字が出力される。
    • 古いdvipdfmxでもサポートしている。
  • 欠点
    • UnicodeのTFMにしか通用しない。
      • つまり、pTeXでは使えないし、japanese-otfの\CIDも全く使えなくなる。
    • Unicode文字に対する既定のグリフしか使えない。
    • このため、標準和文フォントにおいてJIS X 0208の範囲の一部の文字が使えない可能性が生じる。
      • ②と同じ。
    • フォントの中で異なるUnicode文字が同じグリフを共有する場合、文字情報(ToUnicodeの結果)が“変な文字”になる可能性がある。(“部首文字問題”が発生しうる。)

古いdvipdfmxの場合、AJ1でないOpenTypeフォントではこの③しか使えない。

Unicode直接指定+フィーチャ指定

%rml は無理
uprml-h     unicode             HogeraMincho-Regular.otf -l jp90
uprml-hq    unicode             HogeraMincho-Regular.otf -l fwid
%hminr-h は無理
%hminrn-h は無理
otf-ujmr-h  unicode             HogeraMincho-Regular.otf -l jp90
otf-ujmrn-h unicode             HogeraMincho-Regular.otf -l jp04
%otf-cjmr-h は無理
(標準和文を2004JIS字形にしたい場合は以下のようにする)
uprml-h     unicode             HogeraMincho-Regular.otf -l jp04

③の拡張版で、Unicode値によりグリフを選ぶ際にOpenTypeフィーチャを有効にする。最近(20170918版以降)のdvipdfmxでのみサポートされる。

uprml-hの0x2603   ―→   U+2603のjp90指定のグリフ
  • 利点
    • AJ1でないOpenTypeフォントにも適用できる。
    • 必ず入力したUnicodeの文字が出力される。
    • Unicode文字に対するグリフをある程度制御できる。
      • クオートは全角幅で出力される。
  • 欠点
    • 新しいdvipdfmxでしかサポートしていない。
    • UnicodeのTFMにしか通用しない。
    • フォントの中で異なるUnicode文字が同じグリフを共有する場合、文字情報(ToUnicodeの結果)が“変な文字”になる可能性がある。(“部首文字問題”が発生しうる。)

ひとまずまとめ

だめだ dvipdfmxのフォントマップ なにもわからない

(つづけ)

  1. (u)pLaTeXでパッケージを何も用いられない場合の和文フォントとして使われる和文TFMのこと。以下では「標準和文」と呼ぶ。

  2. AJ1のOpenTypeフォントについては①が最適である。TrueTypeフォントについては、昔は④は使えなかったし、③はほとんどの場合に②に劣るのでわざわざ選択する必要がない。

チョットpdfTeXでTrueTypeフォントしてみる話

チョット調べてみたところ、某マクロツイーターでは2011年に書かれた一連の「TeXのフォントの取扱」に関する解説記事の中で少しだけ「pdfTeXでTrueTypeフォントする話1」に触れられている。

zrbabbler.hatenablog.com

とはいえ、その記事では「dvipdfmxでOpenTypeフォントする話」のおまけのような扱いに留まっている感じもする。そこで、改めて「pdfTeXでTrueTypeフォントする」方法についての完結した記事を書くことにする。ただし単発の記事で完結させるために以下の方針をとる:

  • 動作原理などの詳細については過去の記事の方に全て任せることにして、ここでは手順だけを述べる。
  • 話を単純にするため、「フォントの中の1つのグリフだけを使えるようにする」というケースについて扱う。

pdfTeXで素敵に源真ゴシックする話

題材として「源真ゴシック」を使うことにする。源真ゴシックには2万弱のグリフがあるが、その中で一つだけ使いたいグリフを選ぶとなると、当然コレになるだろう。

f:id:zrbabbler:20190921032125p:plain
源真ゴシックのU+2603(SNOWMAN)

というわけで、このグリフのみを(文字コード0の位置に)含む本質的なTeX欧文フォント(TFM)である「genshinessential-r」を作成することにする2

※もちろん源真ゴシックの☃は「源ノ角ゴシック」の☃そのものであるが、源ノ角ゴシックはCFFグリフのOpenTypeフォントであるため、ここでは使えない。

encファイルをつくる

文字コード0をU+2603にマップする」ようなエンコーディングを表すencファイル「essential.map」を作る。

[essential.map]
/essential-enc [
/u2603
] def

少し補足しておくと、encファイルの書式は以下の通りである。

/エンコーディング名 [
/文字コード0に対するグリフ名
/文字コード1に対するグリフ名
/文字コード2に対するグリフ名
・・・・・・
/文字コード255に対するグリフ名
] def

「グリフ名とは何か」というのは本当はヤヤコシイ話なのであるが、ここで紹介する手順に従う(otftotfmを使う)のであれば、単純に「U+2603のグリフ名はu26033と考えてかまわない。

エンコーディング名」については後の設定と整合する限りは勝手に決めてかまわない。

encファイルの仕様としては必ず文字コード0~255に対するグリフ名を書く必要があり、今回のように「0しか使わない」という場合でも、残りの255個の位置に“未定義”を表す.notdefというグリフ名を並べる必要がある。でもどうやらotftotfmでは後ろの.notdefは省略しても通用する4ようなので、ここでは横着をした。

TFMをつくる

このessential.encとフォントファイルGenShinGothic-Regular.ttfを入力として、otftotfmを用いてTFMを作成する5

※入力ファイルはカレントディレクトリに置いておく。

otftotfm -e essential.enc GenShinGothic-Regular.ttf genshinessential-r >genshinessential.map

ここで標準出力をリダイレクトしていることに注意。otftotfmはpdfTeX用のマップ行を標準出力に出すので、これをgenshinessential.mapに保存しておく。このコマンドの実行により、以下のファイルが生成される。

  • genshinessential-r.tfm: TFMファイル。
  • a_fdlbd4.enc6: 元のessential.encを“加工”して作られたencファイル。実際にpdfTeXで使うのはこちらの方である。(essential.encはもはや不要。)
  • genshinessetial.map: pdfTeX用のマップファイル。

otftotfmは“間にVFを挟んだTFM”を生成する7ことが多いのであるが、今回は非常に単純な事例であったため単純に.tfmファイル一つだけからなるTFMになったようだ。

早速pdfTeXでgenshinessentialしてみる

これで“TeXレベル”でgenshinessential-rを利用するための準備は全て整った。そこでまずはplain pdfTeXの文書で動作をテストしてみる8

[test-plain.tex]
% plain pdfTeX document
% マップファイル読込の指定
\pdfmapfile{+genshinessential.map}
% TFM"genshinessential-r"からフォント \fEsssential を生成
\font\fEssential=genshinessential-r
% フォントを \fEssential に切り替えてコード0のグリフを出力
Test: {\fEssential\char0}
\bye

plain pdfTeXなのでpdftexコンパイルする。

pdftex test-plain

端末出力をみると、今の作業で作ったファイルや源真ゴシックのフォントファイルがちゃんと読み込まれていることが確認できる。

(./test-plain.tex{c:/texlive/2019/texmf-var/fonts/map/pdftex/updmap/pdftex.map}
{genshinessential.map} [1] ){a_fdlbd4.enc}<c:/texlive/texmf-local/fonts/truetyp
e/public/GenShinGothic/GenShinGothic-Regular.ttf><c:/texlive/2019/texmf-dist/fo
nts/type1/public/amsfonts/cm/cmr10.pfb>
Output written on test-plain.pdf (1 page, 14867 bytes).

そして出力されたtest-plain.pdfの中身を確認すると……。

f:id:zrbabbler:20190921044841p:plain
plain pdfTeXな出力結果

素敵☃!

今度はpdfLaTeXでgenshinessentialしてみる

無事にplain TeXで源真ゴシックできたので次はLaTeXでのサポートについて考えることにしよう。

LaTeXのサポートというと「当該のフォント(ファミリ)に切り替える命令」を提供するのが普通であるが、今の事例ではそれは意味を成さないだおる。今作ったTFMは「文字コード0しかない」という特殊なものであり、それでできることは「源真ゴシックの☃を出す」ことだけなので、そのための専用の命令を用意するべきだろう。そこで、LaTeXパッケージ「genshinessential」の設計について、次のような方針にする。

  • 「源真ゴシックのU+2603〈☃〉を出力する」ための命令\genshinsnowmanを提供する。
  • U+2603のグリフにはシェープ(ウェイトなど)による差異が元々存在しない。だから、単一のシェープのみを定義して、\genshinsnowmanは常にそれを使うことにする。
  • マップファイルをパッケージファイルと別に用意する必然性は乏しいので、パッケージ中でマップ行を宣言することにする。

現状のマップ行自動生成の名前が入っていて少し汚らしいので整理しよう。まずは、a_fdlbd4.encの先頭の部分(%00の行より前)を次のように書き換えたものを新たにessential.encとして保存する。(つまり、a_fdlbd4.encの代わりにessential.enc、AutoEnc_fdl・・・2raの代わりにessential-encを使うようにする。)

/essential-enc [
%00
  /uni2603 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
  /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
・・・・・・

パッケージファイルgenshinessential.styの実装は次のようにした。

※マップ行でessential.encや/essential-encを使っていることに注意。

[genshinessential.sty]
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{genshinessential}

% マップ行読込の指定.
\pdfmapline{+genshinessential-r GenShinGothic-Regular "essential-enc ReEncodeFont" <[essential.enc <GenShinGothic-Regular.ttf}

% ファミリ'genshinessential'の定義.
% エンコーディングは'U'(不定形)を指定する.
\DeclareFontFamily{U}{genshinessential}{}
% m/nシェープしか使わないのでそれだけを定義する.
\DeclareFontShape{U}{genshinessential}{m}{n}{<->genshinessential-r}{}

%<*> \genshinsnowman: "源真ゴシック"のU+2603を出力する.
\newcommand{\genshinsnowman}{{\usefont{U}{genshinessential}{m}{n}\symbol{0}}}

これでLaTeXのサポートが完成したことになる。改めて整理すると:

  • genshinessential-r.tfm: TFMファイル。
  • essential.enc: (判りやすい名前の)encファイル。
  • genshinessetial.sty: LaTeXパッケージファイル。

早速genshinessetialパッケージを使ってみよう。

[test-latex.tex]
% pdfLaTeX document
\documentclass[a4paper]{article}
% 素敵なパッケージを読み込もう
\usepackage{genshinessential}
\begin{document}
% 素敵な命令を使おう
Hello \genshinsnowman\ world!
\end{document}

もちろん今度はpdflatexでコンパイルする。出力結果は……。

f:id:zrbabbler:20190921051700p:plain
pdfLaTeXな出力結果

トッテモ素敵☃!

まとめ

源真ゴシックの☃は素敵!


  1. 当該の記事ではTrueTypeフォントだけに限らず一般のOpenTypeフォント(TrueTypeグリフもCFFグリフも含めて)が対象になっている。実際、pdfTeXで両種のOpenTypeフォントが扱えるのであるが、CFFグリフのOpenTypeについては「サブセット埋込ができない」という重大な制限がある。このため、実用的に使えるのは専らTrueTypeフォントに限られることになるだろう。

  2. 「genshinessential-r」の名前は例によって“ZR命名規則”に依る。エンコーディング不定形(1つしかグリフがない)なので省略し、バリアント部を「r」(Regular)、ファミリ部を「genshinessentia」とした。

  3. Unicode値は「4桁以上の大文字16進数で書く」という規則なので、例えばU+0038ならu0038、U+1F92Eならu1F92Eがグリフ名となる。uni2603というグリフ名も可能だが、この方式は5桁以上では使えない。

  4. 最初に手動で作るencファイルはotftotfmの入力となった後は一切使われない。

  5. TrueTypeフォントが与えられた場合、Type1への変換は非対応であるため--no-type1--no-dotlessjは事実上常に有効になる。今の目的に照らすとOpenTypeフィーチャ(-f ligaなど)を指定する必要もないだろう。

  6. 生成されたencファイルの名前(およびその中に記されたエンコーディング名)は自動生成されるので、環境によって異なる可能性がある。

  7. VFが使用された場合、「genshinessential-r.tfm」の他に「genshinessential-r.vf」と「genshinessential-r–base.tfm」が生成されるはずである。つまり、「genshinessential-r」は「genshinessential-r–base」を参照するVFである。

  8. pdfTeXの普通のマップ設定に割り込むのは面倒なので、代わりに「文書内で(\pdfmap...プリミティブで)マップ設定を行う」という方法をとる。詳細については[過去の記事]の方を参照。

scsnowmanでつくる対称コルーチン(※最新の定義)

猛暑! 台風! ゆきだるま☃︎

コルーチンのイロイロな定義

某ZR氏の某ツイッタァーをフォローしている方ならご存知だと思いますが、去る5月30日に、某出版社の某『n月刊ラムダノート』の創刊を記念したパーティーが催されました。

このパーティーにおいてメインのテーマとなったのが、

コルーチンの定義がイロイロありすぎてアレ

ということでした。この話題についての詳細は以下の記事に譲ることにしますが、要するにコルーチンの定義が本質的に問題なわけです。

コルーチンの素敵な定義

この問題に対して、そのパーティとは全然サッパリ関係のない某ZR氏が、画期的な解決法を提案しています。

スバラシイ☃︎

scsnowmanで対称コルーチン(※最新の定義)したい話

せっかくコルーチンの定義が素敵☃︎になったのですから、LaTeXのscsnowmanパッケージを使ってコルーチン(※最新の定義)に関する技術文書を作りたくなりますね。ところが、ここで大きな問題があります。それは、

対称コルーチン(※最新の定義)は対称でないといけない

ということです。

f:id:zrbabbler:20190808163349p:plain
対称コルーチン(※最新の定義)

一方で、scsnowmanで出力されるゆきだるま☃︎は、どれも素敵ですが非対称です。

かの画期的なscsnowmanパッケージも対称コルーチン(※最新の定義)はサポートできないのでしょうか。いや、決してそんなことはありません。実は、scsnowmanには「ゆきだるま形状をユーザが独自に定義する」ための機能が用意されています。

Any users can define and use custom snowman shape definitions. Here is a description of adding a shape named myfavorite.
  1. Prepare a snowman definition file scsnowman-myfavorite.def and put it into $TEXMF tree (e.g. texmf-local/tex/latex/scsnowman/). (後略)
  2. (scsnowman マニュアル; §6 “Adding User-defined Snowman Shapes”)

つまり、対称なゆきだるま形状を定義したファイルscsnowman-zrsymmetric.defを用意すれば、次のようにして対称なゆきだるまが出力できるはずです。

% pdfLaTeX document
\documentclass[a4paper]{article}
\usepackage{scsnowman}% ゆきだるま!
\usescsnowmanlibrary{zrsymmetric}% 対称!
\begin{document}
% 'shape'キーで形状を指定する
\scsnowman[shape=zrsymmetric,‹他オプション›...]
\end{document}

scsnowmanで対称コルーチン(※最新の定義)する話

というわけで、作ってみました

早速、対称コルーチン(※最新の定義)をつくってみましょう。

% upLaTeX文書
\documentclass[uplatex,dvipdfmx]{jsarticle}
\usepackage[a6paper,scale=0.75]{geometry}
\usepackage{xcolor,scsnowman}
\usescsnowmanlibrary{zrsymmetric}% 対称ゆきだるま
\begin{document}
非対称コルーチン
\scsnowman[hat=green!35!black,arms=green!20!black,
buttons=green!35!black,snow,muffler=green!50!black,
adjustbaseline,scale=2]% フツー(非対称)
も、対称コルーチン
\scsnowman[hat=green!35!black,arms=green!20!black,
buttons=green!35!black,snow,muffler=green!50!black,
adjustbaseline,scale=2,shape=zrsymmetric]% 対称!
もどちらも素敵なので、
両者は等価です。
\end{document}

f:id:zrbabbler:20190808180932p:plain
コルーチン(※最新の定義)に関する技術文書

バッチリですね!

イロイロな対称ゆきだるま

形状オプションshape=zrsymmetricを付けた場合でも、\scsnowmanの他のオプション(hatmuffler、などなど)は自由に設定できます。

% pdfLaTeX document
\documentclass{article}
\usepackage[a6paper,scale=0.75]{geometry}
\usepackage[svgnames]{xcolor}
\usepackage{scsnowman}
\usescsnowmanlibrary{zrsymmetric}% 対称!
%% \CompareSnowmen{<オプション>...}
% 非対称と対称のゆきだるまを並べて出力する.
\newcommand{\CompareSnowmen}[1]{\par
  \scsnowman[scale=4,#1]%
  \scsnowman[scale=4,shape=zrsymmetric,#1]%
  \par\smallskip}
\begin{document}
% シンプル
\CompareSnowmen{hat,arms,snow,muffler}
% ミカン付き
\CompareSnowmen{mouthshape=tight,
  mikan=Orange,leaf=Olive,sweat=SkyBlue}
% 箒付き
\CompareSnowmen{hat=Green,arms=Brown,muffler=Red,
  buttons=Blue,snow=SkyBlue,broom=DarkGoldenrod}
\end{document}

f:id:zrbabbler:20190808181012p:plain
イロイロな対称ゆきだるま(非対称もあるよ)

scsnowmanのゆきだるまの多様性がもっともっと増えたわけですね。スバラシイ☃︎

まとめ

というわけで、非対称コルーチン(※最新の定義)も、対称コルーチン(※最新の定義)も、それ以外のゆきだるま☃︎も、すべて素敵!

Markdownでデカイ文字を書けて便利な話(ただしPandoc)

聞くところによると、Markdownでとにかくデカイ文字が簡単に書けると便利なようです。

しかし残念なことに、元来のMarkdownは意味的なマークアップを指向したものであるため、今世にあるMarkdownの各種方言はどれも「見出しを書く」ことができても「デカイ文字を書く」ことができません。このことがデカイ文字の熱狂的ファンがMarkdownの採用を躊躇する一因となっていることは否めないでしょう。

というわけで、Markdownでデカイ文字を書くためのPandocフィルタを作ってみました

文字をデカくする

このフィルタを使う場合、デカイ文字は「bigクラスをつけたspan要素」として表されます。Pandoc Markdownの記法では次のように書きます。

[sample1.md]

Pandocは[アレ]{.big}。

早速このMarkdownをHTMLに変換してみましょう。

pandoc sample1.md --lua-filter biggggg.lua -s -o sample1.html

f:id:zrbabbler:20190731210533p:plain
HTMLでデカイ文字

デカイ! 便利!

今度はLuaLaTeX経由でPDFに変換してみましょう。

pandoc sample1.md --lua-filter biggggg.lua -o sample1.pdf --pdf-engine=lualatex -V documentclass=bxjsarticle -V classoption=pandoc

f:id:zrbabbler:20190731210622p:plain
PDFでデカイ文字

デカイ! 便利!

※現状では、対応する出力形式はHTMLとLaTeX(経由のPDF)に限ります。

文字をもっともっとデカくする

「これだけのデカさでは物足りない」という人はもっともっとデカイ文字も使えます。クラス名としてbigの代わりにbiggbigggbigggg、……とすることで、文字をどんどんデカくできます。

[sample2.md]

Pandocは[アレ]{.bigg}[アレ]{.bigggg}
[アレ]{.bigggggg}[アレ]{.bigggggggg}。

※見やすさのため、Markdown中に改行を入れました。この改行は(空白にならずに)無視されてほしいので、pandoc実行時にオプションに-f markdown+ignore_line_breaksを追加することにします。

f:id:zrbabbler:20190731210654p:plain
HTMLでもっともっとデカイ文字
f:id:zrbabbler:20190731210716p:plain
PDFでもっともっとデカイ文字

もっともっとデカイ! 便利!

強調文字もデカくする

もちろん、デカイ文字を他の文字装飾と組み合わせることもできます。

[sample3.md]

Pandocは[アレ]{.bigg}、TeXは[超絶**アレ**]{.bigggggg}。

f:id:zrbabbler:20190731211010p:plain
HTMLでデカイ強調文字
f:id:zrbabbler:20190731211035p:plain
PDFでデカイ強調文字

強調付きでデカイ! 便利!

まとめ

Pandocはネタ記事を書くのに便利!(えっ)

PandocでWindowsをシャットダウンする件について

皆さんもよくご存知の通り、LuaLaTeXでは「Windwosをシャットダウンする文書」が作成できます。これはLuaコードを通じて(C言語コンパイルして生成した)マシン語のプログラムが実行できることを利用しています。

ところで、以前のネタで紹介した通り、PandocではLuaでフィルターを実装することができます。となると、マークダウンという不思議な形式の文書でWindowsをシャットダウンしてみたくなるのは当然の帰結でしょう。

どうもPandocでWindowsをシャットダウンできそうにない件

Luaでバイナリ(マシン語)のモジュールを作製する際には、次のような感じのC言語の関数を実装します。

※以下のコードはLuaLaTeXのやつで使っているモジュール1ソースコードからの抜粋。

/* Opens the module.
 */
__declspec(dllexport) int luaopen_shutwindown(lua_State *L) {
    luaL_newlib(L, registry);
    return 1;
}

Luaでモジュールを読み込む(require "shutwindown")と、この関数が実行されるのですが、この中で使われているluaL_newlibというのは「Lua処理系の連携用API」の一つです。連携APILua処理系と外部のコードの間のやり取りを行う機構で、バイナリのモジュールの実装に不可欠なものです。

つまり、バイナリのモジュールを動作させるには、Lua処理系の連携APIの関数が「外から見えている」必要があるわけです。TeX Live配布におけるLuaTeXのLua処理系は動的リンクのライブラリ(WindowsだとDLL形式)になっているため、連携APIは外から見えています。これに対して、Pandocの公式のWindwos用バイナリではLua処理系が静的にリンクされていて連携APIが外から見えません。これではLuaTeXの時と同じようには「Windowsをシャットダウンするモジュール」を実装することはできません。

それでもPandocでWindowsをシャットダウンしたい件

絶望的な状況になっていしまいましたが、もう少し考えてみましょう。

先程述べた通り、Luaコードにおいてモジュールshutwindownの読込(require)を行うとC言語の関数luaopen_shutwindownが呼ばれます。Luarequire "shutwindown"に対応する動作なので、通常はこの関数では「モジュールの関数を収めたLuaテーブルを作成して返す」ことが期待されています。しかし、とにかくモジュールの実装コードに実行を移すことができているのだから、ここで早々とシャットダウン開始の処理を済ませてしまえばいいわけです。

/* Opens the module.
 */
__declspec(dllexport) int luaopen_shutwindown(void *L) {
    shutdown_system(); /* シャットダウン! */
    return 0;
}

すなわち、このモジュールがインストールされたLua処理系では、require "shutwindown"を実行するだけでシャットダウンが開始します。

改めてPandocでWindowsをシャットダウンする件

というわけで、作ってみました

このリポジトリにあるファイルpcshutwindown.dllとshutdown.luaをカレントディレクト2に置いた上で、何か適当なMarkdown文書’(リポジトリにあるREADME.mdでもいいでしょう)をPandocで変換しましょう。もちろんフィルタにshutdown.luaを指定することを忘れずに。

C>pandoc README.md --lua-filter shutdown.lua
System will be shutdown in 10 seconds...
System will be shutdown in 9 seconds...
System will be shutdown in 8 seconds...
System will be shutdown in 7 seconds...
System will be shutdown in 6 seconds...
System will be shutdown in 5 seconds...
System will be shutdown in 4 seconds...
System will be shutdown in 3 seconds...
System will be shutdown in 2 seconds...
System will be shutdown in 1 second...
FAREWELL!

f:id:zrbabbler:20190616011206p:plain

まとめ

結局、PandocのLuaフィルタでバイナリモジュールを利用するのは難しい、のかな?


  1. 当該の記事を書いたときには、当時のLuaTeXに合わせてLua 5.1版を前提にした実装でしたが、現在(TeX Live 2019以降)のLuaTeXのLua処理系は5.3版であるため、5.3版で動作するように改修しました。

  2. Pandocの公式バイナリではLuaのバイナリモジュール読込パスにはカレントディレクトリが含まれています。

「サイゼリヤで1000円あれば最大何kcal摂れるのか」をSATySFiで解いてみた

SATySFiをオワコンにしてしまうのは忍びないので、やってみた

作ったもの

このsaizeriyaパッケージを使うとSATySFi文書中でサイゼリヤ問題ができるようになる。

[saizeriya-test.saty]

@require: stdja
@require: saizeriya
%saizeriya.satyhをカレントに置く場合は↓を使う
%@import: saizeriya

%------------------------------------------------- メニューデータ
let the-menu = [
(|calorie=130;cost=299;name=`彩りガーデンサラダ`|);
(|calorie=115;cost=349;name=`小エビのサラダ`|);
(|calorie=134;cost=299;name=`やわらかチキンのサラダ`|);
(|calorie=92;cost=299;name=`わかめサラダ`|);
……(中略)……
(|calorie=164;cost=369;name=`トリフアイスクリーム`|);
]
%------------------------------------------------- 本文
in

document (|
  title = {\SATySFi;でサイゼリヤ問題};
  author = {某ZR(アレ)};
  show-title = true;
  show-toc = false;
|) '<                                          
  +section{問題}<
    +p{
      予算1000円以内で,サイゼリヤで最大カロリーを摂取するような
      注文の仕方を求めよ。
      ただしサイゼリヤの料理のメニューは以下の通りとする。
    }
    %the-menuのメニューを箇条書きで出力する
    +saizeriya-listing-menu(the-menu);
  >
  +section{解答}<
    +p{
      以下の通り。
    }
    %サイゼリヤ問題を解いて解答を表組で出力する
    +saizeriya-tabular-solution(the-menu)(1000);
  >
>

この文書をコンパイルすると次の出力が得られる。

※SATySFiの0.0.3版を使用。

f:id:zrbabbler:20190528215346p:plain
「問題」の出力の冒頭

f:id:zrbabbler:20190528215409p:plain
「解答」の出力

まとめ

というわけで、SATySFiは非オワコンで素敵!

「サイゼリヤで1000円あれば最大何kcal摂れるのか」をPandocで解いてみた

どうやら、TeXを使うと計算と組版を一気にやってしまえて最高、なようです。

ところで、皆さんご存知の通りTeXアレなわけですが、どうやら聞くところによると、Pandocも相当アレなようです。

となると、サイゼリヤで1000円あれば最大何kcal摂れるのか」をPandocで一気に計算して組版する、というネタがあって然るべきなのは、当然の帰結でしょう。

というわけで、やってみました

方針

サイゼリヤ問題を解くMarkdown文書

[sample.md]

# 問題

予算1000円以内で,サイゼリヤで最大カロリーを摂取するような注文の仕方を求めよ。ただしサイゼリヤの料理のメニューは以下の通りとする。

[一覧](./menu.csv){.saizeriya-list}

# 解答

以下の通り。

[解答](./menu.csv){.saizeriya-solve badget=1000}

[menu.csv]

彩りガーデンサラダ,130,299
小エビのサラダ,115,349
やわらかチキンのサラダ,134,299
わかめサラダ,92,299
イタリアンサラダ,196,299
……(略)……

書式の説明

特定のクラスを付けたリンク要素を書くと、その部分がフィルタによって置き換えられます。

次のように、クラスにsaizeriya-listを指定したリンクを書くと、指定のメニューファイルを読み込んでメニューの一覧の箇条書きを生成してその場に出力します。(テキストは出力されません。)

[テキスト](メニューファイルのパス){.saizeriya-list}

クラスにsaizeriya-solveを指定したリンクを書くと、指定のメニューファイルを読み込んでサイゼリヤ問題を解き、その解答を表組にしたものを出力します。この際に予算額badgetという属性で指定します。

[テキスト](メニューファイルのパス){.saizeriya-solve badget=予算額}

さっそくPandocしてみる

以下のコマンドで、先のMarkdown文書(sample.md)をWord文書に変換します。

pandoc sample.md --lua-filter=saizeriya.lua -o sample.docx

※「Wordは嫌だ」という人は、出力ファイル名のsample.docxの拡張子を変えて別の形式を選びましょう。例えばsample.odtとするとOpenDocument形式になります。sample-out.mdのようにすると別ファイルにMarkdown形式で出力できます。

出力されたWord文書(sample.docx)を開いてみると、メニュー一覧が正しく挿入されていることが判ります。

※以下の出力結果はPandoc 2.7.2(最新版)によるものです。

f:id:zrbabbler:20190525154330p:plain
sample.docx 1ページ目冒頭

そして、最後のページをみると、例の栄養満点な3点セットが、無事に出力されていました。

f:id:zrbabbler:20190525154405p:plain
sample.docx 4ページ目

まとめ

たとえTeX言語ができなくても、Pandocがあれば計算と組版を一気にやれます! スゴイ!(えっ)