Glyph Bitmap Distribution Format (BDF) というフォントフォーマットがあります。
記事の最後の方に書いたような理由があって、 BDF を読み込むパッケージを書いています。
道半ばなのですが、お試しで使えるくらいにはまとまったので、一旦出力しておこうと思った次第。
今回書いた BDF をパースする方法は、仕様上は安全でない可能性があるのですが、それに関しては記事を改めて考察することにしたいと思います。
BDF をコンソールに表示してみる
これを使って実際に文字を表示してみます。 まずは iex でお手軽に試します。
パッケージをインストールする
まだ hex.pm に公開していないので、GitHub のリポジトリを指定してインストールしてください。
mix.exs
でインストールする場合:
defp deps do [ {:bdf, github: "mattsan/bdf"} ] end
iex やスクリプトファイルでインストールする場合:
Mix.install([{:bdf, github: "mattsan/bdf"}])
フォントファイルを入手する
BDF ファイルを用意して読み込みます。
今回はパブリックドメインで公開されている東雲フォントを利用させていただきました。
表示したいフォントデータを取得する
東雲フォントは文字コードに JIS を利用しています。 必要に応じて JIS X 0213のコード対応表 などを利用して表示したい文字の文字コードを確認し、フォントデータを取得します。
今回はサンプルということで、特に効率などを考慮せず Enum.find/2
で線形検索しています。
{:ok, fonts} = BDF.load("path/to/shnmk16.bdf") # 入手した BDF ファイルのパスを指定します font = Enum.find(fonts, & &1.encoding == 0x4E6E)
表示する
取得したフォントデータは、点の一つ一つが 1 ビットで表現されているので、それらのビットを見える形に展開して表示します。
Enum.each(font.bitmap, fn row -> for <<dot::1 <- <<row::size(font.bbx.bbw)>> >> do case dot do 0 -> " ." 1 -> "@@" end end |> Enum.join() |> IO.puts() end)
結果。
. . . . . . . . . . . . . . . . . .@@@@@@@@@@@@@@@@@@@@@@@@ . . . . . . . . .@@ . . . . . . . . .@@@@@@@@@@@@@@@@@@@@@@@@@@@@ . .@@ . . . . .@@ . . . . . .@@ . .@@@@@@@@@@ .@@ .@@@@@@@@ .@@ . .@@ . .@@@@@@@@ . .@@@@@@@@@@ . . . . . . . . . . . . . . . . . . . .@@@@@@@@@@@@@@@@@@@@ . . . . . . . . . . . . . . . . . . . .@@@@@@@@@@@@@@@@@@@@@@@@@@@@ . . . . . . .@@ . .@@ . .@@ . . . . . .@@ . .@@ . .@@ . .@@ . . . . . . .@@ .@@ . .@@ .@@ . . . . .@@@@@@@@@@@@@@@@@@@@@@@@@@@@ . . . . . . . . . . . . . . . . .
BDF を Livebook で表示してみる
Livebook を使えば簡単に画像で確認することもができるので、これもやってみます。
パッケージをインストールする
mattsan/bdf
の他に、画像を表示すために kino
と、PNG データを生成するために拙作の pngex
も合わせてインストールします。
Mix.install([ {:kino, "~> 0.12.3"}, {:pngex, "~> 0.1.2"}, {:bdf, github: "mattsan/bdf"} ])
BDF ファイルを読み込む
読み込みは iex で試したときと変わりません。 ダウンロードした BDF ファイルを読み込みます。
{:ok, fonts} = BDF.load("path/to/shnmk16.bdf")
フォントデータを画像に変換する
pngex
を使って画像に変換します。
ここではパレットカラーを使い、 1 ビット / ドットの画像を生成しています。
palette = [ {255, 255, 255}, # 背景: 白 {0, 0, 0} # 文字: 黒 ] font1 = Enum.find(fonts, & &1.encoding == 0x4E6E) font2 = Enum.find(fonts, & &1.encoding == 0x4C74) bitmap = for row <- font1.bitmap ++ font2.bitmap, into: <<>> do <<row::size(font1.bbx.bbw)>> end Pngex.new() |> Pngex.set_type(:indexed) |> Pngex.set_depth(:depth1) |> Pngex.set_size(font1.bbx.bbw, font1.bbx.bbh + font2.bbx.bbh) |> Pngex.set_palette(palette) |> Pngex.generate(bitmap) |> IO.iodata_to_binary()
Livebook での表示の様子。
表示が小さいので縦横 4 倍のサイズにしてみます。
palette = [ {255, 255, 255}, # 背景: 白 {0, 0, 0} # 文字: 黒 ] font1 = Enum.find(fonts, & &1.encoding == 0x4E6E) font2 = Enum.find(fonts, & &1.encoding == 0x4C74) bitmap = for row <- font1.bitmap ++ font2.bitmap, into: <<>> do line = for <<dot::1 <- <<row::size(font1.bbx.bbw)>> >>, into: <<>> do case dot do 0 -> <<0::4>> 1 -> <<0xF::4>> end end String.duplicate(line, 4) end Pngex.new() |> Pngex.set_type(:indexed) |> Pngex.set_depth(:depth1) |> Pngex.set_size(font1.bbx.bbw * 4, (font1.bbx.bbh + font2.bbx.bbh) * 4) |> Pngex.set_palette(palette) |> Pngex.generate(bitmap) |> IO.iodata_to_binary()
解像度の低いディスプレイに似合いそうな表示が得られました。
そんなわけで、Nerves 再起動
開発が進んでいる様子のコメントがされつつも、なかなか公開に至っていなかった Circuits.GPIO ですが、満を持してバージョン 2.0 が今月公開されました。
それに刺激を受けて、5 年ほど放置していた Nerves プログラミングを再開。
(デバイスは RPI-ZERO-WH Raspberry Pi Zero WH【ピンヘッダ実装済】 + WaveShare 13891 1.44インチ 128×128 LCDディスプレイHAT for RaspberryPi )
そのうち、何かおもしろいものを出力できるといいな。 そのうち。