[自作キーボード]QMKファームウェアでカラーLCDに対応する~フォント表示~

目次

Abstract

  • 前回の続きでQuantum Painterについて
  • ST7789のLCDにフォント(テキスト)を表示した

Introduction

前回はST7789のLCDに円や四角形などの簡単な図形を表示するところまでやったので、今回はフォントの表示をやってみます。

Method

参考:Quantum Painter

フォントの表示処理は↑のQMKのgithubに詳細があります。
今回は、以下の手順で実施していきます。

  1. フォントファイル(.ttf)を中間ファイル(.png)に変換する
  2. 中間ファイルをQFFファイル形式※に変換する
  3. QFFファイルをファームウェアに組み込む
  4. フォントの表示処理を記述する

※QFFファイル形式: QMK用のフォントデータ。中身はc言語ソースで画像データが配列の形で格納されるっぽい。


1. フォントファイルを中間ファイルに変換する

参考: qmk painter-make-font-image

  • painter-make-font-imageというコマンドでTTF形式のフォントファイルをPNG形式に変換します
  • 使い方の詳細は↑のリンクを参照。
  • 最低限必要な引数は、入力するTTFフォントファイル名と出力ファイル名
  • デフォルトだと変換対象はASCII文字のみです。日本語(ひらがな、カタカナ、漢字)とかが必要であれば-uオプションを使う
  • 引数の説明
    • -u
      • ASCII以外の文字列を使用したい場合に指定する
    • -s
      • フォントのサイズを指定する。デフォルトは12px
      • 1.3inch, 240x240のLCDに対して12pxだとかなり小さいので今回は32pxを指定
  • 今回は入力には以下のフォントを使用しました。

実行結果

(venv) user@user:~/qmk$ qmk painter-make-font-image -s 32 -o JetBrainsMono-Regular.png -f JetBrainsMono-Regular.ttf
(venv) user@user:~/qmk$

成功すると以下のような中間ファイルが生成されます。
JetBrainsMono-Regular.png JetBrainsMono-Regular.png


2. 中間ファイルをQFF形式に変換する

参考: qmk painter-convert-font-image

  • 上のリンクを参考に中間ファイル(PNG)をQFF形式に変換します
  • コマンドの引数は↑のリンクを参照
    • 最低限必要なのは入力と出力フォーマットの指定のみ
      • 出力フォーマットは白黒で使うならmono4(4階調グレースケール), mono16(16階調グレースケール)辺りで良さそう

実行結果

(venv) user@user:~/qmk$ qmk painter-convert-font-image -i JetBrainsMono-Regular.png -f mono16
Writing /home/user/qmk/JetBrainsMono-Regular.qff.h...
Writing /home/user/qmk/JetBrainsMono-Regular.qff.c...

成功すると~.qff.h, ~.qff.cの1組のCソース・ヘッダーファイルが出力されます


3. QFFファイルをファームウェアに組み込む

生成したフォントファイルを自分のキーボード用ファームの置き場に置く

自分の例だと以下。config.hとかある場所にqffディレクトリを作成してその中に配置しました。(特に指定は無いので、後のパス指定さえちゃんとすれば、どこにおいても問題ないとは思いますが。。)

  • qmk_firmware/keyboards/cepst/
    • rp2040test // 自分のキーボードファームのソース置き場
      • keymaps/
      • qff/ <-追加
        • JetBrainsMono-Regular.qff.h <-追加
        • JetBrainsMono-Regular.qff.c <-追加
      • config.h
      • etc.

rules.mkに追記

生成したQFFファイルをコンパイル対象に含めるため、rules.mkに追記します。

↓rules.mk

QUANTUM_PAINTER_ENABLE = yes
QUANTUM_PAINTER_DRIVERS += st7789_spi

SRC += qff/JetBrainsMono-Regular.qff.c  // <-追記

keymap.cに生成したQFFのヘッダファイルをインクルードする

QFFのヘッダーファイルをkeymap.cでインクルードする

↓keymap.c

#include QMK_KEYBOARD_H
#include <qp.h>
#include "qff/JetBrainsMono-Regular.qff.h"  // <-追記
// ~以下省略~

コンパイルを試す
特に問題なくコンパイルできました。この状態でファームウェアにQFF形式のフォントデータが組み込まれており、画像データの分だけファームウェアサイズなども大きくなっていました。


4. フォントの表示処理を記述する

keymap.cにフォントの表示処理を記載する

参考: Font Functions

上記リンクにフォント表示関連のAPIの説明があります。
フォント表示に必要な処理は以下。

  1. 背景描画
  2. フォントのロード
  3. フォントの表示

上記の処理をkeymap.cに追加したコードが以下。

#include QMK_KEYBOARD_H
#include <qp.h>
#include "qff/JetBrainsMono-Regular.qff.h"  // <-追記

static painter_device_t lcd;

enum HSL
{
    HUE,
    SAT,
    VAL,
};
const uint8_t black[] = {0,   0,   0};
const uint8_t white[] = {0,   0,   255};
const uint8_t red[]   = {0,   255, 127};
const uint8_t blue[]  = {170, 255, 127};

enum Position
{
  X,
  Y,
};

// フォントハンドルの宣言
static painter_font_handle_t fontHandle;

// 表示する文字列の宣言
static const char *text1 = "test";
static const char *text2 = "Hello World!";

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT_ortho_2x3(
        KC_A,    KC_B,    KC_C,
        KC_D,    KC_E,    KC_F
    )
};

void keyboard_post_init_user(void)
{
    setPinOutput(LCD_BACKLIGHT_PIN);
    writePinHigh(LCD_BACKLIGHT_PIN);

    lcd = qp_st7789_make_spi_device(LCD_HEIGHT, LCD_WIDTH, SPI_CS_PIN, SPI_MISO_PIN, LCD_RESET_PIN, SPI_DIVISOR, SPI_MODE);
    qp_init(lcd, QP_ROTATION_0);
    qp_power(lcd, true);
    qp_clear(lcd);

    /* 描画処理 */
    uint16_t startPos[] = {0, 0};
    uint16_t endPos[] = {LCD_WIDTH, LCD_HEIGHT};

    // 背景描画
    qp_rect(lcd, startPos[X], startPos[Y], endPos[X], endPos[Y], white[HUE], white[SAT], white[VAL], true);

    // フォント描画処理(追記)
    fontHandle = qp_load_font_mem(font_JetBrainsMono_Regular);
    if(fontHandle != NULL)
    {
        // 左上原点に描画
        qp_drawtext(lcd, startPos[X], startPos[Y], fontHandle, text1);

        // 上下左右中央揃え、フォント色変更して描画
        int16_t text2_width = qp_textwidth(fontHandle, text2);
        startPos[X] = (LCD_WIDTH / 2) - (text2_width / 2);
        startPos[Y]= (LCD_HEIGHT / 2) - (fontHandle->line_height / 2);
        qp_drawtext_recolor(lcd, startPos[X], startPos[Y], fontHandle, text2, red[HUE], red[SAT], red[VAL], white[HUE], white[SAT], white[VAL]);
    }
}

keymap.cに追加した処理の説明

背景描画

  • フォントの描画処理だけを作成すると、下記のようにフォントの描画をしたところ以外の領域がモザイク状になるみたいです
  • そのため、一度全画面をqp_rect()で塗りつぶす処理を入れたほうが良さそうです

モザイク状に表示される例
mosaic

フォントのロード処理

  • 下記の関数を使ってフォントをロードする
  • 引数のbufferはフォントデータを指定する
    • 2で変換した~.qff.cにフォントデータ配列が下記のように定義されているので、その配列の変数名を指定すれば良い
      • 下記の例だと, “font_JetBrainsMono_Regular"を指定する

↓qmk_firmware/keyboards/cepst/rp2040test/qff/JetBrainsMono-Regular.qff.c

#include <qp.h>

const uint32_t font_JetBrainsMono_Regular_length = 16089;

// clang-format off
const uint8_t font_JetBrainsMono_Regular[16089] = {
    0x00, 0xFF, 0x14, 0x00, 0x00, 0x51, 0x46, 0x46, 0x01, 0xD9, 0x3E, 0x00, 0x00, 0x26, 0xC1, 0xFF,
    0xFF, 0x23, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0xFF, 0x01, 0xFE, 0x1D, 0x01, 0x00, 0x13, 0x00,
~~省略

フォントの描画処理

(補足)描画するテキストの長さと高さを図る方法
表示座標を計算する際にテキストの長さと高さがほしい場合は以下の方法で取得可能

  • 長さを取得する方法
    • qp_textwidth()
  • 高さw取得する方法
    • fontHandle->line_height
      • qp_load_font_mem()で得られるフォントハンドルからアクセス演算子で取得できる

Result

上記で変更したrules.mk, keymap.cを使ってコンパイルを実行し、作成したファームウェアを書き込んだ結果が以下。無事にテキストが表示できた。

font
※LCDの下部の黒っぽい線はLCD自体の傷です。。。

Conclusion

今回はLCDにフォントを表示してみました。フォントが表示できるとレイヤー情報、入力しているキー、打件数とか色々なパラメータを動的に表示できるようになるので楽しくなりますね。
ただ、quantum painterでのフォントの組み込みはフォントサイズ一つにつき、一つのファイルを組み込む必要があるようなので、大きい文字と小さい文字を表示したいみたいな場合だと、複数のフォントファイル(~.qff.c)をファームウェアに組み込む必要が出てくるのが少しめんどくさいです。。

次回はLCDに画像を表示したいと思います。



Appendix

ASCII以外の文字列(日本語等)をLCDに表示する場合

qmk painter-make-font-image, qmk painter-convert-font-image-uオプションを使うことで日本語(ひらがな、カタカナ、漢字)を含めたUnicode文字をQFFファイルに入れ込むことができます。最終的にファームウェアに入れ込む際には必要な文字列だけ指定する形となってます。

下記の例では、-nオプションを併用してASCII文字を除いて、「ハロー・ワールド」という文字列のみを含んだフォントファイルを生成している。

(venv) user@user:~/qmk$ qmk painter-make-font-image -s 16 -f NotoSansJP-ExtraBold.ttf -n -u "ハロー・ワールド" -o NotoSansJP-ExtraBold_16px_ja.png
(venv) user@user:~/qmk$ qmk painter-convert-font-image -i NotoSansJP-ExtraBold_16px_ja.png -f mono16 -n -u "ハロー・ワールド"
Writing /home/user/qmk/NotoSansJP-ExtraBold_16px_ja.qff.h...
Writing /home/user/qmk/NotoSansJP-ExtraBold_16px_ja.qff.c...

生成されたpngファイル
ja font

上記の日本語フォントファイル(~ja.qff.h, ~ja.qff.c)を使って日本語フォントを表示させた例