Ubuntu ServerのCUI環境（tty）のフォントを変更する

## 前置き
Raspberry Pi 4 Model B Rev 1.5にUbuntu Server 22.04.4を入れて、ディスプレイを直接繋いだ状態で遊んでいます。つまり、デスクトップ環境ではなく、他のマシンからSSHなどで繋ぐのでもなく、CUI環境（tty）を触っている状態です。
ttyで表示されていたデフォルトのフォント（後述しますが、Uni2-Fixed16という（？）やつみたいです）は比較的見やすくてかわいいと思ったのですが、普段Windowsで開発する際はConsolasを愛用しており、それに変えられないのかな？と思ったのがスタートになります。
以下、`sudo`は省略します。またデフォルトで入ってなくて`apt`でインストールしたやつがどれだか忘れてしまったので、必要があれば適宜`apt install`してください。
## 前提
まず大前提として、ttyにおけるフォントは、現在多くを占めるTTF（TrueType Font）やOTF（OpenType Font）ではなく、PSF（PC Screen Font）というものになります。
したがって、例えばUbuntu Desktop環境でよくやられるように`apt install fonts-noto-cjk`とやってNotoをインストールする、みたいなことをやったとしても、それはPSFではないため、ttyのフォントとしてそのまま使うことは出来ません。
## 既定のフォントから選ぶ、あるいはフォントサイズを変える
まず、既定のフォントから選んだりフォントサイズを変えたりする方法です。
下記のコマンドによってウィザードが展開されます。
```
# dpkg-reconfigure console-setup
```
順番に、「エンコーディング」「文字セット」「フォント」「フォントサイズ」を選択することができます。このうち「エンコーディング」「文字セット」は、特に変える必要はないと思います。
「フォント」の選択肢として主に「Fixed」「Terminus」「VGA」という3種類が存在しており、「Fixed」を基準とすると「Terminus」は特に小文字が少し小ぢんまりとしてよりかわいく、「VGA」は縦線が太まって凛々しいフォントになっています。

ちなみに、現在のコンソールのフォントを変えるというだけなら、`setfont`というコマンドがあります。このコマンドでPSFファイル（またはそのGZ圧縮ファイル）を指定すれば、即座にフォントが変わります。既定のフォントのファイルは`/etc/console-setup/`または`/usr/share/consolefonts/`に存在しているため、例えば
```
# setfont /etc/console-setup/Uni2-VGA16.psf.gz
```
のようにしてフォントを試すことができます。
ちなみに、PSFファイルはGZ圧縮してもしなくても使えるみたいです。
## TrueType/OpenType Fontを何とかして使う
さて、「Terminus」フォントが予想以上に刺さるかわいさだったのでこれで良しとしてもよかったのですが、どうにかして当初のきっかけであったConsolasも使えないものかともう少し調べてみました。
結論としては、「使えるといえば使えるが、期待するものではない可能性が高い」ということになりました。
手順ですが、TTF/OTFファイルをまずBDF（Bitmap Distribution Format）ファイルというものに変換し、BDFファイルからPSFファイルを作成することで、目的を達成することが可能です。
これらはそれぞれ`apt`でインストール可能なツールが存在しており、`otf2bdf`および`bdf2psf`というコマンドを利用することができます。
### TTF/OTFファイル -> BDFファイル
あらかじめ、TTFファイル（ここでは**consola.ttf**とします）が手に入っているものとします。
まず`otf2bdf`コマンドにより、下記でBDFファイルが作られます。
```
# otf2bdf -o consola.bdf consola.ttf
```
既定では標準出力されるようになっており、`-o`引数の後ろで出力ファイルを指定する形です。ちなみにBDFファイルはテキスト形式なので、中身を確認することも可能です。ここがポイントです。
なお、既定では12px・解像度100（？）として出力され、`-p`でフォントサイズ、`-r`で解像度を変更することが可能になっています。TTF/OTFファイルはベクターであるため、この引数によってビットマップとして表示する上でのサイズが決まってくるのだという理解です。
### BDFファイル -> PSFファイル
`bdf2psf`コマンドですが、結局まだ仕様を完全に把握できていません。が、まず使い方を。**consola.bdf**から**consola.psf**を作成するには下記コマンドになります。
```
# bdf2psf --fb consola.bdf /usr/share/bdf2psf/standard.equivalents /usr/share/bdf2psf/ascii.set 256 consola.psf
```
これで動けばいいのですが、多くの場合エラーが出てしまいます。エラーの一つとして、`the width is not integer number.`というものがあります。`/usr/bin/bdf2psf`ファイルを直接見てみれば分かるのですが、BDFファイルの中の`AVERAGE_WIDTH`というものが10の倍数じゃないとこのエラーが発生するようです。なので、BDFファイルを直接いじって`AVERAGE_WIDTH`のところを近い値で10の倍数に書き換えたうえで、上記コマンドを実行します。これでPSFファイルが手に入ります。
ただ念のため、この時点で、前述の`setfont`が有効だったPSFファイルパスを正確に確認しておいてください。
PSFファイルが正常に出力できていれば、`setfont consola.psf`などとやって生成したフォントを確認することが可能です。しかし、場合によってはファイルに不具合のある可能性があり、そうなると`setfont`を実行したとき画面表示が破壊されます。
こうなってしまうと、今何を入力しているのかさえ目で見て確認することが出来なくなるので、あらかじめ有効だったPSFファイルをブラインドで打ち込んで元に戻すということが必要になるわけです。
また、`AVERAGE_WIDTH`を10で割った値はそれが画面上の文字の横幅になるという理解ですが、すなわち例えば`AVERAGE_WIDTH 20`などのような指定をしてしまうと、横幅2pxとなってとても読めないフォントになってしまいます。
`AVERAGE_WIDTH`の値は前述の`otf2bdf`の引数によっても変わってくるので、いろいろ試してみるのも面白いと思います。
あと、`WARNING: U+0023 no glyph defined`といった警告が出るケースもあります。これは、未確認ですが、描画されるべき範囲に適切な文字が描画されていないのかなと思っています。これが出た場合、そのUnicode文字は文字化けしてしまいます。
## 環境への適用
冒頭で述べたように、`setfont`コマンドを使えば現在のフォントを変更することが可能ですが、`reboot`をすると元々のフォントに戻ってしまいます。これを恒久的な設定とするためには、`/etc/default/console-setup`の編集をする必要があります。このファイルは、例えば以下のような記述になっています。
```
# CONFIGURATION FILE FOR SETUPCON

# Consult the console-setup(5) manual page.

ACTIVE_CONSOLES="/dev/tty[1-6]"

CHARMAP="UTF-8"
FONTFACE="Terminus"
FONTSIZE="8x16"

VIDEOMODE=

# The following is an example how to use a braille font
# FONT='lat9w-08.psf.gz brl-8x8.psf'
```
詳細は割愛しますが、上のほうは前述の`dpkg-reconfigure console-setup`ウィザードで設定される内容となります。なので、FONTFACEなどをここで変更しても、同ウィザードで再設定すると上書きされるため、このあたりはいじらなくてよいです。
下のほうのコメントにも書いてある通りですが、このファイルの末尾に、先ほど生成したPSFファイルに関する設定を書き加えます。
```
FONT="consola.psf"
```
この設定は、絶対パス指定でも有効ですが、デフォルトで`/etc/console-setup/`フォルダと`/usr/share/consolefonts/`フォルダを探しに行ってくれるので、いずれかのフォルダにPSFファイルを置いておけば絶対パス指定にする必要はありません。
設定を保存したら、下記コマンドで適用されます（-vは詳細表示用のパラメーターです）。
```
# setupcon -v
```
あるいは、下記でも反映されます。
```
# service console-setup restart
```
または、`reboot`でもOKです。
### setfontでは反映されるのに上記コマンドでフォントが変わらない場合
残念なことに、原因はよくわからないのですが、`setfont`ではフォントが適用されるのに`setupcon`などでは反映されない場合があります。ここまでの手順を追って作成したPSFファイルは大丈夫な気がしますが、ネット上から直接PSFファイルをダウンロードした場合に、うまくいかないケースがありました。（例えばこのファイルだとダメでした：[**ter-powerline-v16n.psf.gz**](https://github.com/powerline/fonts/blob/master/Terminus/PSF/ter-powerline-v16n.psf.gz)）
この場合、一旦BDFファイルを作り直してPSFファイルにしたところ、うまくいきました。
まず、[**ここ**](https://gist.github.com/froh/1bb10ce5752f37eefe1b)からPSF→BDF変換するPerlスクリプトをダウンロードします。これはBDF形式のテキストを標準出力するようになっているので、
```
# perl psf2bdf.pl ter-powerline-v16n.psf | tee ter-powerline-v16n.bdf
```
としてあげると、PSFファイルからBDFファイルが作成できます。ただ、例によって`bdf2psf`でうまくいかない箇所があるため、このBDFファイルを開いて、
```
FONT_ASCENT 16
FONT_DESCENT 0
AVERAGE_WIDTH 80
```
という3行を`ENDPROPERTIES`行の手前に挿入します。本当なら数値をきちんと決める必要がある気はするのですが、とりあえず動いたので深追いはしていません。
追記したら前述の`bdf2psf`コマンドを通して、改めてPSFファイルを作成します。そうすると、`setupcon`が効くようになっているのではないかと思います。
## 結果
さて、こうして作成してきた結果として、**consola.psf**で実際に表示してみたのがこちらになります。（少々パラメーターをいじってあります）
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3736537/5a10c236-77a2-f0e4-42a3-6cb48c9451f5.png)

確かにConsolasの面影はあるのですが、何かこう刺さるものがない…。もしかしたらパラメーターをチューニングして改善されるのかもしれませんが、今のところあまりお気に入りのものは作れませんでした。
結局、ConsolasのWindowsでの見やすさは、アンチエイリアスとかなんかいろいろ効いている結果なのかなと思いました。
## あとがき
本記事では、TTFフォントからttyで使えるフォントを作成しました。多分、文字化けの問題や文字が不足している問題（上図で`????`になっているような部分）について漏れがありますので、今後もっと勉強出来たらいいなと思います。

自分は、今のところは標準のTerminus（下画像）がお気に入りになったので、これを使いたいと思います。（えぇ…）
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3736537/05eab6e7-935b-3c03-dbbf-a805aefe16d3.png)