M5Stack:日本語でこんにちワールド!

MicroPythonから、日本語も表示させてみたいところです。日本語のフォントを用意して、それをフォントで指定すればいいんじゃないかな?って思ってたのですが…。


フォントの生成

TTF形式のフォントファイルから、M5Stackで使えるフォントファイルを生成するツールがGItHubのM5Cloudサンプルのところにありました。

Font Tool
https://github.com/m5stack/M5Cloud/tree/master/examples/Display/font_tool

これ使って、日本語フォントからフォントファイル生成してみたのですが…。
あれ?これって1バイトフォントしか対応できない…?

日本語フォントファイル生成は残念ながら手詰まりとなってしまいました。


他の人はどうやっているのかな?もし、生成済みのフォントがあったら、流用させてもらえるといいなー、とか思いながら、検索してみますと

M5Stackで日本語表示させてみる
https://qiita.com/inachi/items/0e492a6b00d31111e54d

M5stack ( ESP32搭載 )の LCD に日本語漢字フォントを表示したりスクロールしたり
https://qiita.com/inachi/items/0e492a6b00d31111e54d

日本語表示については「フリーフォントファイルのフォーマット形式を理解して、がんばってプログラムで自分で描画する!」みたいですね。

「フォント用意して指定すればいい!」みたいな簡単にはいかなかったか。


文字描画プログラム作ろう!

ひとまず、ひらがなだけでやってみます。

「M+ BITMAP FONTS」のフリーフォントを使わせてもらいました。

M+ BITMAP FONTS
http://mplus-fonts.osdn.jp/mplus-bitmap-fonts/

フォントの形式は、BDF形式です。ファイルの内容はテキストファイルで、「BITMAP」の下の英数字が文字フォントのビットマップデータですね。

JISコード表を見ながらフォントのコードを確認。

「あ」は「0x2422」です。mplus_j12r.bdf のファイル該当箇所は、こういうデータでした。

STARTCHAR 0x2422
ENCODING 9250
SWIDTH 886 0
DWIDTH 12 0
BBX 12 13 0 -2
BITMAP
0000
0400
04C0
7F00
0800
0F80
1940
2920
4A20
4C20
3440
0180
0000
ENDCHAR

これのBITMAP部分をPythonの配列で保持。使いやすいようにディクショナリにしておきました。

fontDataDict = {
 "あ":[0x0000,0x0400,0x04C0,0x7F00,0x0800,0x0F80,0x1940,0x2920,0x4A20,0x4C20,0x3440,0x0180,0x0000]
}

表示ロジックは、1つずつデータを読み込んで、地道にピクセル描画。

def printChar(char, base_x, base_y):
 if char in fontDataDict: #キーがあるか確認
   fontData = fontDataDict[char]
   y = 0
   for fontData_line in fontData: #1行ずつ描画
     for x in range(15):
       if fontData_line >> (15 - x) & 1 == 1: #ビット上側から、1か0かチェック
         lcd.rect((x + base_x)*2, (y + base_y)*2, 2, 2) #1ならその位置にドット打つ(2x2)
     y = y + 1

12ドットはさすがに小さいので、2×2のドットで描画するようにしました。これをjpfont.pyで保存しておいて、main.pyに呼び出し処理を書きます。

from m5stack import lcd
import jpfont
lcd.clear()
jpfont.printChar("あ", 0, 0)

実行すると…

でたー!

同様に、ひらがなを全部登録。

fontDataDict = {
 "ぁ":[0x0000,0x0000,0x0000,0x0000,0x0400,0x3F80,0x0800,0x0F00,0x1A80,0x2A80,0x2C80,0x1900,0x0000],
 "あ":[0x0000,0x0400,0x04C0,0x7F00,0x0800,0x0F80,0x1940,0x2920,0x4A20,0x4C20,0x3440,0x0180,0x0000],
 "ぃ":[0x0000,0x0000,0x0000,0x0000,0x0000,0x2100,0x2100,0x2080,0x2080,0x2480,0x1800,0x0000,0x0000],
 "い":[0x0000,0x0000,0x0000,0x2000,0x2080,0x4040,0x4040,0x4020,0x4220,0x2400,0x1800,0x0000,0x0000],
 "う":[0x0000,0x0000,0x0000,0x2000,0x2080,0x4040,0x4040,0x4020,0x4220,0x2400,0x1800,0x0000,0x0000],
 "ぅ":[0x0000,0x0000,0x0000,0x0000,0x0C00,0x0300,0x0000,0x0700,0x1880,0x0080,0x0100,0x0600,0x0000],
 "う":[0x0000,0x1C00,0x0300,0x0000,0x0E00,0x3100,0x0080,0x0080,0x0080,0x0100,0x0600,0x1800,0x0000],
 "ぇ":[0x0000,0x0000,0x0000,0x0000,0x0C00,0x0300,0x0000,0x1F00,0x0200,0x0400,0x0A00,0x1180,0x0000],
 "え":[0x0000,0x0C00,0x0300,0x0000,0x3F00,0x0100,0x0200,0x0400,0x0C00,0x1200,0x2200,0x41C0,0x0000],
 "ぉ":[0x0000,0x0000,0x0000,0x0000,0x0800,0x0880,0x3E40,0x0800,0x1F00,0x2880,0x2880,0x3300,0x0000],
 "お":[0x0000,0x0800,0x08C0,0x7E20,0x0800,0x0800,0x0F80,0x1840,0x2820,0x4820,0x4840,0x3180,0x0000],
 "か":[0x0000,0x1000,0x1080,0x1080,0x7C40,0x1240,0x1220,0x2220,0x2200,0x4200,0x4200,0x1C00,0x0000],
 "が":[0x0000,0x1040,0x1120,0x1080,0x7C00,0x1240,0x1240,0x2220,0x2220,0x4200,0x4200,0x1C00,0x0000],
 "き":[0x0000,0x0400,0x0580,0x7E00,0x03C0,0x7E00,0x0100,0x1E80,0x2180,0x2000,0x1000,0x0F00,0x0000],
 "ぎ":[0x0040,0x0520,0x0480,0x7E00,0x03C0,0x7E00,0x0100,0x1E80,0x2180,0x2000,0x1000,0x0F00,0x0000],
 "く":[0x0000,0x0000,0x0100,0x0200,0x0400,0x0800,0x1000,0x1000,0x0C00,0x0200,0x0100,0x0080,0x0000],
 "ぐ":[0x0000,0x0000,0x0200,0x0440,0x0920,0x1080,0x2000,0x2000,0x1800,0x0400,0x0200,0x0100,0x0000],
 "け":[0x0000,0x0080,0x2080,0x2080,0x4FE0,0x4080,0x4080,0x4080,0x4080,0x4080,0x2100,0x2600,0x0000],
 "げ":[0x0000,0x0140,0x4120,0x4180,0x9F40,0x8100,0x8100,0x8100,0x8100,0x8100,0x4200,0x4C00,0x0000],
 "こ":[0x0000,0x0000,0x1F80,0x0000,0x0000,0x0000,0x0000,0x1000,0x2000,0x2040,0x1F80,0x0000,0x0000],
 "ご":[0x0000,0x0000,0x3F40,0x0020,0x0080,0x0040,0x0000,0x2000,0x4000,0x4080,0x3F00,0x0000,0x0000],
 "さ":[0x0000,0x0200,0x0200,0x02C0,0x7F00,0x0100,0x0100,0x1E80,0x2180,0x2000,0x1000,0x0F00,0x0000],
 "ざ":[0x0000,0x0840,0x0920,0x0E80,0xF800,0x0400,0x0200,0x3D00,0x4300,0x4000,0x2000,0x1E00,0x0000],
 "し":[0x0000,0x0000,0x0800,0x0800,0x0800,0x1000,0x1000,0x1000,0x1040,0x1040,0x0880,0x0700,0x0000],
 "じ":[0x0000,0x0000,0x1080,0x1240,0x1100,0x2000,0x2000,0x2000,0x2080,0x2080,0x1100,0x0E00,0x0000],
 "す":[0x0000,0x0200,0x0200,0xFFE0,0x0200,0x0E00,0x1200,0x1200,0x0E00,0x0200,0x0400,0x1800,0x0000],
 "ず":[0x0000,0x0200,0x0200,0xFFE0,0x0200,0x0E40,0x1220,0x1280,0x0E40,0x0200,0x0400,0x1800,0x0000],
 "せ":[0x0000,0x0080,0x1080,0x1080,0x13E0,0x7C80,0x1080,0x1080,0x1380,0x1000,0x1000,0x0FC0,0x0000],
 "ぜ":[0x0000,0x0100,0x2140,0x2120,0x2780,0xF940,0x2100,0x2100,0x2700,0x2000,0x2000,0x1F80,0x0000],
 "そ":[0x0000,0x0000,0x1F80,0x0100,0x0200,0x0400,0x7FE0,0x0400,0x0800,0x0800,0x0800,0x0780,0x0000],
 "ぞ":[0x0000,0x0000,0x3E40,0x0320,0x0480,0x0800,0xFFC0,0x0800,0x1000,0x1000,0x1000,0x0F00,0x0000],
 "た":[0x0000,0x1000,0x1000,0x7F80,0x1000,0x13C0,0x1000,0x2200,0x2400,0x2400,0x43E0,0x4000,0x0000],
 "だ":[0x0040,0x1120,0x1080,0x7F00,0x1000,0x13C0,0x1000,0x2200,0x2400,0x2400,0x43E0,0x4000,0x0000],
 "ち":[0x0000,0x0400,0x0400,0x05E0,0x7E00,0x0800,0x1700,0x1880,0x0040,0x0040,0x0080,0x0F00,0x0000],
 "ぢ":[0x0040,0x0920,0x0880,0x0F00,0xF800,0x1000,0x2E00,0x3100,0x0080,0x0080,0x0100,0x1E00,0x0000],
 "っ":[0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0E00,0x3100,0x0080,0x0080,0x0100,0x0E00,0x0000],
 "つ":[0x0000,0x0000,0x0000,0x0F00,0x7080,0x0040,0x0040,0x0040,0x0080,0x0300,0x1C00,0x0000,0x0000],
 "づ":[0x0040,0x0120,0x0080,0x0F00,0x7080,0x0040,0x0040,0x0040,0x0080,0x0300,0x1C00,0x0000,0x0000],
 "て":[0x0000,0x0000,0x0000,0x0FC0,0xF200,0x0400,0x0800,0x0800,0x0800,0x0800,0x0400,0x0380,0x0000],
 "で":[0x0000,0x0000,0x0000,0x0FC0,0xF200,0x0440,0x0920,0x0880,0x0800,0x0800,0x0400,0x0380,0x0000],
 "と":[0x0000,0x0800,0x0800,0x0800,0x0400,0x0780,0x0C00,0x1000,0x2000,0x2000,0x1000,0x0F80,0x0000],
 "ど":[0x0080,0x1240,0x1100,0x1000,0x0800,0x0F00,0x1800,0x2000,0x4000,0x4000,0x2000,0x1F00,0x0000],
 "な":[0x0000,0x0800,0x08C0,0xFE20,0x1000,0x1080,0x2080,0x2080,0x4780,0x48C0,0x08A0,0x0700,0x0000],
 "に":[0x0000,0x0000,0x2000,0x23C0,0x4000,0x4000,0x4000,0x4200,0x4400,0x4400,0x23E0,0x2000,0x0000],
 "ぬ":[0x0000,0x0200,0x0200,0x2200,0x2F80,0x3240,0x2220,0x5420,0x55A0,0x4A60,0x3240,0x01A0,0x0000],
 "ね":[0x0000,0x1000,0x1000,0x1000,0x7380,0x1440,0x1820,0x1020,0x31A0,0x5260,0x1240,0x11A0,0x0000],
 "の":[0x0000,0x0000,0x0000,0x0F80,0x1440,0x2420,0x4420,0x4820,0x4820,0x3040,0x0180,0x0000,0x0000],
 "は":[0x0000,0x0080,0x2080,0x2080,0x4FE0,0x4080,0x4080,0x4080,0x4780,0x48C0,0x28A0,0x2700,0x0000],
 "ば":[0x0000,0x0140,0x4120,0x4180,0x9F40,0x8100,0x8100,0x8100,0x8F00,0x9180,0x5140,0x4E00,0x0000],
 "ぱ":[0x0000,0x00C0,0x4120,0x4120,0x9FC0,0x8100,0x8100,0x8100,0x8F00,0x9180,0x5140,0x4E00,0x0000],
 "ひ":[0x0000,0x0000,0x7900,0x0900,0x1080,0x20C0,0x20A0,0x4080,0x4100,0x4100,0x2200,0x1C00,0x0000],
 "び":[0x0000,0x0040,0x7920,0x0880,0x1000,0x2080,0x20C0,0x40A0,0x4100,0x4100,0x2200,0x1C00,0x0000],
 "ぴ":[0x0000,0x00C0,0x7920,0x0920,0x10C0,0x20A0,0x2080,0x4080,0x4100,0x4100,0x2200,0x1C00,0x0000],
 "ふ":[0x0000,0x0000,0x1F00,0x0100,0x0200,0x0400,0x2440,0x2440,0x2220,0x4220,0x4220,0x0C00,0x0000],
 "ぶ":[0x0000,0x0040,0x1F20,0x0180,0x0240,0x0400,0x2400,0x2440,0x2240,0x4220,0x4220,0x0C00,0x0000],
 "ぷ":[0x0000,0x00C0,0x1F20,0x0120,0x02C0,0x0400,0x2400,0x2440,0x2240,0x4220,0x4220,0x0C00,0x0000],
 "へ":[0x0000,0x0000,0x0000,0x0000,0x0000,0x3800,0x4400,0x8200,0x0180,0x0060,0x0000,0x0000,0x0000],
 "べ":[0x0000,0x0000,0x0080,0x0240,0x0100,0x3800,0x4400,0x8200,0x0180,0x0060,0x0000,0x0000,0x0000],
 "ぺ":[0x0000,0x0000,0x0180,0x0240,0x0240,0x3980,0x4400,0x8200,0x0180,0x0060,0x0000,0x0000,0x0000],
 "ほ":[0x0000,0x0000,0x2FE0,0x2080,0x4080,0x4FE0,0x4080,0x4080,0x4780,0x48C0,0x28A0,0x2700,0x0000],
 "ぼ":[0x0000,0x0040,0x5F20,0x4180,0x8100,0x9FC0,0x8100,0x8100,0x8F00,0x9180,0x5140,0x4E00,0x0000],
 "ぽ":[0x0000,0x00C0,0x5F20,0x4120,0x81C0,0x9F00,0x8100,0x8100,0x8F00,0x9180,0x5140,0x4E00,0x0000],
 "ま":[0x0000,0x0200,0x0200,0x7FC0,0x0200,0x3FC0,0x0200,0x0200,0x1E00,0x2380,0x2240,0x1C00,0x0000],
 "み":[0x0000,0x0000,0x7C00,0x0480,0x0480,0x0480,0x3F80,0x48C0,0x88A0,0x9080,0x6100,0x0600,0x0000],
 "む":[0x0000,0x0800,0x0800,0x7EC0,0x0820,0x0800,0x3800,0x4800,0x4840,0x3840,0x0840,0x0780,0x0000],
 "め":[0x0000,0x0200,0x0200,0x2200,0x2F80,0x1240,0x3220,0x5420,0x4C20,0x4820,0x3040,0x0180,0x0000],
 "も":[0x0000,0x0800,0x0800,0x7F80,0x0800,0x0800,0x7F80,0x1000,0x1040,0x1040,0x0880,0x0700,0x0000],
 "ゃ":[0x0000,0x0000,0x0000,0x0000,0x0200,0x1200,0x1700,0x3A80,0x0880,0x0900,0x0400,0x0400,0x0000],
 "や":[0x0000,0x0100,0x1100,0x11C0,0x1720,0x1920,0x6820,0x04C0,0x0400,0x0400,0x0200,0x0200,0x0000],
 "ゅ":[0x0000,0x0000,0x0000,0x0000,0x0200,0x2200,0x2780,0x2940,0x3140,0x1780,0x1100,0x0200,0x0000],
 "ゆ":[0x0000,0x0100,0x0100,0x47C0,0x4920,0x5120,0x5120,0x2120,0x27C0,0x2100,0x0100,0x0600,0x0000],
 "ょ":[0x0000,0x0000,0x0000,0x0000,0x0200,0x0200,0x0380,0x0200,0x0E00,0x1300,0x1280,0x0C00,0x0000],
 "よ":[0x0000,0x0400,0x0400,0x0400,0x0780,0x0400,0x0400,0x0400,0x3C00,0x4700,0x4480,0x3800,0x0000],
 "ら":[0x0000,0x0C00,0x0300,0x0000,0x2000,0x2000,0x2700,0x3880,0x0040,0x0040,0x0180,0x0E00,0x0000],
 "り":[0x0000,0x0000,0x1080,0x1080,0x1080,0x1080,0x1080,0x1480,0x0880,0x0080,0x0100,0x0600,0x0000],
 "る":[0x0000,0x0000,0x1F80,0x0100,0x0200,0x0700,0x1880,0x2040,0x0C40,0x1240,0x1280,0x0F00,0x0000],
 "れ":[0x0000,0x1000,0x1000,0x1000,0x7380,0x1440,0x1840,0x1040,0x3080,0x5080,0x1080,0x1060,0x0000],
 "ろ":[0x0000,0x0000,0x1F80,0x0100,0x0200,0x0700,0x1880,0x2040,0x0040,0x0040,0x0180,0x0E00,0x0000],
 "ゎ":[0x0000,0x0000,0x0000,0x0000,0x0800,0x0800,0x3B00,0x0C80,0x0880,0x1880,0x2880,0x0B00,0x0000],
 "わ":[0x0000,0x1000,0x1000,0x1000,0x7380,0x1440,0x1820,0x1020,0x3020,0x5020,0x1040,0x1180,0x0000],
 "ゐ":[0x0000,0x0000,0x3E00,0x0200,0x0380,0x1C40,0x2420,0x4420,0x48E0,0x4920,0x3120,0x00C0,0x0000],
 "ゑ":[0x0000,0x3FC0,0x0100,0x0200,0x0F80,0x3040,0x0E40,0x1180,0x1F00,0x0800,0x39C0,0x4620,0x0000],
 "を":[0x0000,0x0800,0x0800,0x7F80,0x1000,0x1C00,0x22C0,0x4700,0x4A00,0x1200,0x1000,0x0F80,0x0000],
 "ん":[0x0000,0x0000,0x0400,0x0400,0x0800,0x0800,0x1600,0x1900,0x2100,0x2120,0x4120,0x40C0,0x0000] 
}

ついでに、文字列から表示する関数も作成。

def printString(string, base_x, base_y):
 offset = base_x
 for c in string:
   printChar(c, offset, base_y) #1文字ずつ描画呼び出し
   offset = offset + 12

やったー!ひらがな制覇!