DevTerm : プリンタフォントの動的入れ替え

[注意] 以下の内容は、DevTerm プリンタプログラム 2022/1/26バージョンに対して行っています。本家プリンタプログラムは、その後のバージョンアップで、標準でTTF フォント&UTF-8対応になっています。


DevTerm の感熱プリンタプログラムにいくつかフォントを追加してみたのですが、フォント種類指定できるのは 0~7 までなので、そんなにたくさん追加できません。なので、外部からフォントファイルを送り込んで、自由に入れ替えする処理を作ってみました。


変更は、devterm_thermal_printer.c だけです。

https://github.com/shikarunochi/DevTerm/blob/main/Code/thermal_printer/devterm_thermal_printer.c

ファイルを入れ替えて、サイト説明にしたがってビルドし、プリンタプログラムを入れ替えてください。元の devterm_thermal_printer.elf はバックアップ取っておいたほうが良いです。

How to run it from source
・make
・sudo systemctl stop devterm-printer
・sudo cp -rf devterm_thermal_printer.elf /usr/local/bin
・sudo systemctl start devterm-printer


フォント入れ替えのコマンドは [DC2 (0x12)] [F (0x46)][WIDTH][HEIGHT] + [フォントファイル] にしました。WIDTHは8の倍数である必要があります。
256文字をASCIIコード順に並べたデータとなります。8×8フォントの場合、1文字データが1バイト(横8ドット)x 8行 =8バイトとなりますので、2048バイトのデータになります。

フォント入れ替え用ヘッダーを

echo -en "\x12\x46\x8\x8" > changeFontCommand8x8

のようにファイルで作っておいて、

cat changeFontCommand8x8 mz80font.dat > /tmp/DEVTERM_PRINTER_IN

のようにすれば、フォントが登録されて、自動的にフォント切り替えまで行います。

(↑ Tweet の例は、8×8 フォント専用で作ってた時なので、引数が違ってます)

フォント番号 7番で登録してますので、他のフォントに変更した後に再度切り替える場合は、フォントデータ再読み込みしなくても、[ESC (0x1b)] [ ! (0x21)] [7]でフォントを 7番に切り替えればOKです。

echo -en "\x1b\x21\x7" > /tmp/DEVTERM_PRINTER_IN

エミュレータ用に公開されている、PC-6001用互換フォントを使ってみます。(公開されている方に感謝します!)

PC-6001mkII/6601用互換BASIC
http://000.la.coocan.jp/p6/basic66.html#cgrom

PC-6001は、フォントサイズが 8×12 で、ちょっと特殊な感じですね。フォント内容を表示させてみます。

import sys
with open(sys.argv[1], "rb") as fontFile:
    while True:
        fontByte = fontFile.read(1)
        if len(fontByte) == 0:
            break
        fontData = int.from_bytes(fontByte, byteorder='big')
        print('{:02X}'.format(fontData) + ":", end="")
        for i in range(8):
            if fontData & (0x80 >> i) > 0:
                print("■", end = "")
            else:
                print(" ",end = "")
        print();

12バイトフォントデータがあり、その後4バイト空いて、次のフォントデータが入っているようです。フォントデータとして使うなら途中の4バイトを読み飛ばせば良さそう。

ということで、Pythonなら、こういう感じで変換。フォントデータは 12×256 = 3072バイトになります。

with open("cgrom.60", "rb") as fontfile:
    with open('pc6001font.dat', 'wb') as output:
        for i in range(256):
            #12バイト読み、4バイト飛ばす
            output.write(fontfile.read(12))
            fontfile.read(4)

8×12ドット用のフォント入れ替えヘッダを作成して

echo -en "\x12\x46\x8\xc" > changeFontCommand8x12

フォント入れ替え!

cat changeFontCommand8x12 pc6001font.dat > /tmp/DEVTERM_PRINTER_IN

うまく出力できましたー。


ファイルサイズは、必ず WIDTH x HEIGHT / 8 になるようにしてください。プリンタ側のプログラムで余分なデータを読み捨てできればよかったのですが、うまい方法が思いつかなかったので…。フォントファイルのほうが指定より大きかった場合は、データが文字列としてプリンタから出力されてしまいますので、変な印刷が始まってヤバそうと思ったら感熱紙のムダを防ぐために、感熱紙を本体から外して印刷が収まるのを待つと良いです。


MZ-80K/C のフォント(8×8ドット)の場合、ディスプレイコード順をアスキーコード順に並べ替える必要があります。

ascii2disp = [
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6b,0x6a,0x2f,0x2a,0x2e,0x2d,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x4f,0x2c,0x51,0x2b,0x57,0x49,
0x55,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x52,0x59,0x54,0x50,0x40,
0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xdf,0xe7,0xe8,0xe9,0xea,0xec,0xed,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xc0,
0x80,0xbd,0x9d,0xb1,0xb5,0xba,0xb4,0x9e,0xb2,0xb6,0xb9,0xbe,0x9f,0xb3,0xb7,0xbb,
0xbf,0xa3,0x85,0xa4,0xa5,0xa6,0x94,0x87,0x88,0x9c,0x82,0x98,0x84,0x92,0x90,0x83,
0x91,0x81,0x9a,0x97,0x93,0x95,0x89,0xa1,0xaf,0x8b,0x86,0x96,0xa2,0xab,0xaa,0x8a,
0x8e,0xb0,0xab,0x8d,0xa7,0xa8,0xa9,0x8f,0x8c,0xae,0xac,0x9b,0xa0,0x99,0xbc,0xb8,
0x40,0x3b,0x3a,0x70,0x3c,0x31,0x5a,0x3d,0x43,0x56,0x3f,0x1e,0x4a,0x1c,0x5d,0x3e,
0x5c,0x1f,0x5f,0x5e,0x37,0x7b,0x7f,0x36,0x7a,0x7e,0x33,0x4b,0x4c,0x1d,0x6c,0x5b,
0x34,0x41,0x35,0x34,0x74,0x30,0x7c,0x75,0x7d,0x4d,0x6f,0x6e,0x32,0x77,0x76,0x72,
0x73,0x47,0x7c,0x53,0x71,0x4e,0x6d,0x48,0x46,0x3d,0x44,0x1b,0x58,0x79,0x42,0x60
]
with open("FONT.ROM", "rb") as fontFile:
    with open('mz80font.dat', 'wb') as datFile:
        for asciiIndex in range(256):
            dispIndex = ascii2disp[asciiIndex]
            fontFile.seek(dispIndex * 8)
            datFile.write(fontFile.read(8))

FM-7(8×8ドット)は、SUBSYS_C.ROM イメージの先頭にフォントデータが入ってるので、8×256バイトだけ切り出しすればOKです。

with open("Subsys_c.rom", "rb") as fontFile
    with open('fm7font.dat', 'wb') as datFile:
        datFile.write(fontFile.read(256*8))