Pythonでフォントファイル(ttc)からMicroPython用(LS027B4DH01)のフォントデータを作成する

Share on:

MicroPythonを入れたESP32でLS027B4DH01に文字を表示するために必要なフォントデータをPCでPythonを使って作成しました。

フォントファイルからnumpy配列を作成

フォントファイルからMicroPythonの表示用データを作成するために、まずはPillowで1文字だけの画像を作成しました。使用するフォントはMSゴシックです。Image.new()の最初の引数を’1’とすることでモノクロ画像になります。その画像をnumpy.array()に渡すことでbooleanの配列が得られます。例として「B」の文字を変換してみます。

 1font_path   = 'C:\\Windows\\Fonts\\msgothic.ttc'
 2character = 'B'
 3
 4font = ImageFont.truetype(font_path, font_size)
 5draw = ImageDraw.Draw( Image.new('1', (1, 1), (0)) )
 6text_size = draw.textsize(character, font)
 7
 8image = Image.new('1', text_size, (0))
 9draw = ImageDraw.Draw(image)
10draw.text( (0, 0), character, fill=font_color, font=font )
11
12array = np.array(image)

出力結果

boolean配列をintに変換

booleanのnumpy配列をnumpy.astype(numpy.uint8)に渡すことで0と1のintの配列に変換できます。ここでは符号なし整数uint8としました。

array = array.astype(np.uint8)

出力結果

intの配列を0と1の文字列に変換

1行分のデータを0と1が連続する文字列に変換して、数値データを作成しやすい形式にします。

array = [ ‘'.join([ str(j) for j in i ]) for i in array ]

出力結果

文字列を逆の順番にする

MicroPythonのSPI通信でLS027B4DH01にデータを送る場合、小さいビットから送る必要があったので文字列を反転します。

array = [ i[::-1] for i in array ]

出力結果

文字列を8文字ごとにリストに分ける

16進表記の文字列に変換しやすいように、文字列を8文字ごとのリストとして分割します。

1array = [
2    [
3        s[ cnt*8 : cnt*8+8 ] for cnt in range( int(len(s)/8) )
4    ] for s in array
5]

リストを逆の順にする

文字列を逆にするときと同様に、MicroPythonのSPI通信でLS027B4DH01にデータを送る場合、小さいバイトから送る必要があったので8文字ごとのリストを反転して逆の順番にします。

array = [ ls[::-1] for ls in array ]

8文字ごとのリストを要素ごとに16進数表記の文字列に変換する

MicroPython用のbytearrayを作成するために、文字列を16進数表記に変換します。

1array = [
2    [
3        '\\x' + format( ~int(data, 2) & 0xFF, '02x' ) for data in ls
4    ] for ls in array 
5]

分割されている要素を行単位で結合する

ここまでで文字列の表記についての変換が終わったので、最終的な文字列に変換するために行ごとの要素を結合して1つの文字列にします。

array = [ ‘'.join(ls) for ls in array ]

各行を結合して1つの文字列にする

行ごとの文字列をすべて結合して一つの文字列にします。この文字列の前後に辞書のキーとなる文字列「’B’:」とbytearrayの文字列「bytearray(b”)」を追加します。

1text = "'" + character + "' : bytearray(b'" + ''.join(array) + "')"
2'B' : bytearray(b'\xff\xff\xff\xff\xff\xff\x01\xfe\x01\xf0\x01\xe0\xf1\xc3\xf1\xc7\xf1\xcf\xf1\xcf\xf1\xc7\xf1\xc7\xf1\xe3\x01\xf0\x01\xf8\x01\xe0\xf1\xc3\xf1\xc7\xf1\x8f\xf1\x8f\xf1\x8f\xf1\x8f\xf1\x8f\xf1\xc7\xf1\xc3\x01\xe0\x01\xf0\x01\xf8')

最終的なフォントデータ

最終的なデータはfont_16という辞書が書かれたfont_16.pyというファイルにしました。フォントデータに含まれる文字は0~9、a~z、A~Zでファイルサイズは16KBです。内容は下記のような感じです。

ソースコード

 1from PIL import Image, ImageDraw, ImageFont
 2import numpy as np
 3
 4def character_to_text(font_path, character, font_size, font_color):
 5    font = ImageFont.truetype(font_path, font_size)
 6    draw = ImageDraw.Draw( Image.new('1', (1, 1), (0)) )
 7    text_size = draw.textsize(character, font)
 8
 9    image = Image.new('1', text_size, (0))
10    draw = ImageDraw.Draw(image)
11    draw.text( (0, 0), character, fill=font_color, font=font )
12    
13    # image to numpy array (boolean)
14    array = np.array(image)
15
16    # boolean array to int array
17    array = array.astype(np.uint8)
18
19    # int array to str array
20    array = [ ''.join([ str(j) for j in i ]) for i in array ]
21
22    # str reverse
23    array = [ i[::-1] for i in array ]
24
25    # split 8 bit
26    array = [
27        [
28            s[ cnt*8 : cnt*8+8 ] for cnt in range( int(len(s)/8) )
29        ] for s in array
30    ]
31
32    # reverse byte
33    array = [ ls[::-1] for ls in array ]
34
35    # binary string to hex string
36    array = [
37        [
38            '\\x' + format( ~int(data, 2) & 0xFF, '02x' ) for data in ls
39        ] for ls in array 
40    ]
41
42    # string list join
43    array = [ ''.join(ls) for ls in array  ]
44
45    # string list join
46    text = "'" + character + "' : bytearray(b'" + ''.join(array) + "')"
47
48    return text
49
50def main():
51    font_path   = 'C:\\Windows\\Fonts\\msgothic.ttc'
52
53    characters  = [str(i) for i in range(10)]
54    characters += [chr(i) for i in range(97, 97+26)]
55    characters += [chr(i) for i in range(65, 65+26)]
56
57    text = 'font_16 = {' + '\n'
58
59    for character in characters:
60        text += '    '
61        text += character_to_text(font_path, character, 32, 'white')
62        text += ',\n'
63
64    text = text[0:-2] + '\n' + '}' + '\n'
65
66    with open('font_16.py', mode='w') as f:
67        f.write(text)
68
69if __name__ == "__main__":
70    main()

関連記事