LuaTex-jaでNumber too big.エラーがようやく解消

LuaTexで日本語ドキュメントクラス(ltjsarticle, ltjarticleなど)を処理すると

! Number too big.
ltj@@jfont ->luafunction ltj@@jfont@inner 

l.53 \kanjiencoding{JY3}\selectfont

と言われてしまう、という問題が続いていた。 Manjaro Forumで質問したところ、再現するけどupstreamへ、ということだったのでLuaTeX-jaのほうにご報告させていただいたところ、チケットを切っていただいた

Manjaroではつい先日Texliveが201804にアップデートされたが、この問題はLuaTeX-jaが201806として解決してくださっている。

このため、

$ git clone 'https://scm.osdn.net/gitroot/luatex-ja/luatexja.git'
$ sudo rsync -r luatex-ja/src/ /usr/share/texmf-dist/tex/luatex/luatexja/

とすればとりあえずこの問題は解決する。

だが、今度は

! Undefined control sequence.
\lltjp_um_unmag_fsize: ...@preadjust@extract@font 
                                                  \cs_gset_eq:NN \lltjp_um_f...
l.106 \begin{document}

なんて言われてしまう。 これは、

ltjsarticle + unicode-math で をしていないときに起きるエラーのようです. 別チケットにします.(#38372)

とのことで、チケットを切っていただいた

現在のところkitagawa_testブランチになっているが、恐らく近日中に取り込まれるだろう。 なかなか長い戦いだったが、ようやく論文や教材の清書も捗るというものだ。

ちなみに、この影響でgendoc-pandoc.zshのほうはMathfontに対応した。

DPIと画面サイズとスケーリングとピクセルの話

概念の確認

今やあまり意識されることはないのだが、改めて言うと

  • ディスプレイは多数のドットからできている
  • 1インチ辺あたりいくつのドットがあるかというのがDPIである
  • であるから、DPIというのはXYがある。 ちなみに、ThinkPad X1 Carbon 2017は143x158DPIである。 (ppiといったりもする)
  • このためドットの実寸(正確に言えばドット間隔の実寸)はドット数が多いほうが、そしてディスプレイサイズが小さい方が小さくなる
  • ドット数が一定である場合、ディスプレイが大きくなるほど密度(解像度)は下がる
  • 逆にディスプレイサイズが一定である場合、ドット数が増えるほど密度(解像度)は上がる
  • ピクセル数はディスプレイ表示上の絶対数で、その実寸は変動的
  • cm, inch, mmといった単位は実寸上の絶対値で、実際に何ピクセルで描画するかは変動的
  • ラスターグラフィックス、あるいは固定的ピクセル数で描画されるUIは解像度が向上すると実寸としては小さくなる
  • ベクターグラフィックス、あるいは固定的実数値で描画されるUIは解像度が向上すると描画に使用するピクセル数が増加する

論理上の振る舞い

もともとWindowsは96dpiに固定的に設定されていた。 つまり、実際のディスプレイのDPIがどうであるかということに関係なく 1inch = 96pixels という計算をしていたわけだ。 これにより実数をピクセル数に変換していた。

このことから、また固定的ピクセル数でUIが書かれていたことも相まって、基本的に「解像度が上がるとありとあらゆる部品が小さくなる」という現象が起きていた。 Macも72dpiに固定されていて、同じような事情だった。

Windowsは可変値だが、現在Macは72dpiとして計算しつつ、1ポイントは2pxで表示するように変更された。

正しいのは明らかに正しいDPIを設定できるようにすることである。 というよりも、ディスプレイサイズとピクセル数がわかっていれば正しいDPIが算出できるはずだ。 ディスプレイサイズを論理サイズ(24インチとか)から算出するのは難しいが、そもそもどの製品も同じではないので、メジャーで測れば1分もかからない話だ。

実際、Linux(Unix)においてX Window Systemはそのような方式を取っている。

そしてその上で実寸値で指定するか、あるいは画面に対する相対値で指定すれば画面密度によらないスケーラブルな指定が可能だ。

一般的にウェブUIはピクセル数で指定されている。 文字のような流動的情報はインチで指定するほうが一般的だが、これに従うと高解像度ディスプレイではUIは小さいが文字の大きさは正しくUIに書ける文字が減る、ということになる。

現実のスケール

ところが、現実はそうなっていない。

仕方ない部分もある。 例えばパソコンの場合は、13インチでも15インチでも、21インチでも24インチでも「だいたい100から115dpi」あたりに落ち着く。

これを基準にすると、5インチやそこらで400dpiを越えるスマートフォンが困ってしまう。

これは、パソコンを基準に実寸値で表すと、例えば「幅10インチのウィンドウ」といった場合、5インチのスマートフォンでは2画面分の幅があるすさまじく見づらいUIができあがる。

対してピクセル数で表すのもかなり危険だ。 例えばMimir Yokohamaのウェブサイトは900px幅であり、FullHD液晶の場合半分よりちょっと小さいくらい1なのだが、例えば手元のAxon7の場合WQHDなので幅は1440pxある。だから画面の幅の1/3くらい、実寸では5.18cm = 2.03937inchだが、900pxというと3.2375cmになる。

3.2375cmのウィンドウ、しかもサイドバーつき。視点から近いといってもあまりにも小さい。

スマートフォンをパソコンと同じ基準にするのは、実寸値だろうがピクセル数だろうが、かなり難しいわけだ。

じゃあどうしたか、というと、1px=1ピクセルじゃなくしてしまった。

なにを言っているか意味がわからないだろう。

実はMacも同じで、「1ポイントを2ピクセルで描画する」といったが、実はMacでは「1ピクセル指定しても実際は2ピクセルで表示する」ようになっている。 「密度が高いから従来の倍で表示しちゃおう」というわけだ。実際、Retinaディスプレイは180dpiとかあるので、従来のラスターUIをベクターUIのように扱って144dpi相当で描画されることはそれほど困らない。

技術に明るくないウェブエンジニア諸兄はCSSにこんなことを書いているかと思うが

何も疑問に思わないのだろうか。 1080pxをこえているならスマートフォンでは満たさない可能性が高いが、799pxなら今のスマートフォンは大概満たしているだろう。 だが、実際スマートフォンでこれが適用される可能性はかなり高い。

基本的に現代では96dpiを基準にスケールしている。 つまり、実際には180dpiくらいあるディスプレイなら、1ピクセルを倍で描画する。言い換えると、あたかもピクセル数が半分しかないディスプレイであるかのように扱う。

これは正しいのだろうか?

実際は、結構困る。 というのは、UIでピクセルで指定できない場合というのは普通にあって、この場合画面全体のピクセル数は「本当のピクセル数」を回答する。 これに基づいて割合を決めてピクセル数指定すると実際ははみ出してしまったりするのだ。

また、例えばThinkPad X1 Carbon 2017だと約1.4896倍にスケールする2のだが、900pxは1341px、1080pxは1608pxで表示されることになる。 ディスプレイ全体では1920pxなので、もちろん画面には収まるのだが、タイルした場合は1341pxは画面の半分に収まらないのでサイドバーは表示されなくなる。 「タイルしたときにはギリギリサイドバーが表示されたほうが良い」という私の考えは無碍にされてしまうわけだ。

これは12インチクラスのモバイルラップトップだとさらに厳しい。ThinkPad X280は12.5inchなので計算上は10.9inch->176dpiとなり、 12.1inchのLet’s Note SZに至っては10.5inch->182dpiとなる。 この計算においては、ThinkPad X280の場合幅1047px扱いとなり、1080pxですら満たせない。Let’s Note SZに至ってはギリギリ1000pxを満たす程度だ。

色々難しいのには理解を示したいところだが、現実問題としてこれは望ましくなく、「自分に使いやすい嘘DPIを設定する」以外になくなってしまう。

また、この事情により、以前はスケーリングを想定してフォントサイズはピクセル数からポイント数へと動いてきたのだが、 現在はスクリーンフォントはピクセル数で指定したほうが柔軟にスケールしてくれたりする。

個人的な所感

嘘DPIを設定するようでは、せっかくDPIが設定できることが無意味になってしまうし好ましくないと思う。 そもそも、96dpiを基準に固定したまま何倍にしよう、というのはVGA時代の失敗の繰り返し以外の何者でもないとも思う。

おおよそ正しいアプローチなのだから、DPIとスケール倍率という概念を分離できなかったものか。

実はGNOMEはDPIの設定がなくて、DPIを一切尊重しない。 そのかわり

$ gsettings set org.gnome.desktop.interface scaling-factor 2

のようにしてスケールできるのだが、このスケール、整数しか指定できない。 せめて1.5を指定させてくれとものすごーく言われているのだが(13.3inch, 14inchクラスでFullHDだと140から150程度なので1.5がちょうどよい)、対応の気配はない。

一方、KDE PlasmaはGTK+アプリケーションであっても適切にスケールしてくれるが、あくまでDPIによって自動的にスケールするだけで倍率の指定はできない。

現状で理想的なのは

  • DPIは正確なDPI値を算出する。この状態ではinchやcm指定は厳密に適切な値で表示される。 グラフィッカーには便利な状態
  • これによって自動的にRASTER_SCALEACTUALSIZE_SCALEが表示として倍率として設定される。これによって現在と同じ状態になる
  • RASTER_SCALEはディスプレイの論理ピクセル数に影響する。 つまりRASTER_SCALE=2の状態でFullHDディスプレイなら、水平ピクセル数は960だと回答する
  • RASTER_SCALEを手動設定可能とする。ユーザーは自動設定された値(デフォルト値でもある)を基準に好みに合わせて動かす。これに伴うディスプレイの論理ピクセル数も表示すると親切。
  • グラフィッカーのためにACTUALSIZE_SCALERASTER_SCALEと切り離して設定可能とする。ACTUALSIZE_SCALE=1にすれば1インチは1インチで正しく表示してくれる。

だと思うけれど、きっと誰も聞き入れてくれないだろう…

なお、4kディスプレイにしたWindowser向けにアドバイスとして「このままだと文字が小さいので解像度を1920×1080に設定すると解決するよ」と言っているのをかなり見るのだが、もはやこれは頭痛が痛い…


  1. 「半分よりも小さい」のは、フルHDディスプレイでタイリングしたときにサイドバーを表示させるためだ。

  2. これは、X Window Systemで正確なディスプレイサイズを入力し、精密にスケールできるKDE Plasmaを使った場合の話である。