Adafruit LEDBackpack で GFX のフォント比較

はじめに

前回 Adafruit LEDBackpack を使ってドットマトリクスを触ってみた.

簡単にテキストを表示できるのはありがたいが,8×32 のマトリクスに対して標準フォントはやや大きい.文字を流すなどの工夫をしないと,テキストで表現できる情報量は少ない.

思っていたより GFX でドットマトリクスのフォントを変える記事を書いてる人がいない.フォントを変える需要がないのか,手段を知らずに自前でビットマップ描画処理を書いてるのか,そもそもドットマトリクスで文字を表示して遊ぶ人がいないのか.

何はともあれ,今回は LEDBackpack (正確には Adafruit_GFX)で標準で使えるフォントを比較してみる.

フォントを変える方法

Adafruit_LEDBackpack ではフォント描画の仕組みに Adafruit_GFX を使っているので,Adafruit_GFX が扱えるフォントであれば簡単にドットマトリクスLEDに表示できる.

標準で利用できるフォントは Fonts フォルダに用意されている.

GitHub - adafruit/Adafruit-GFX-Library: Adafruit GFX graphics core Arduino library, this is the 'core' class that all our other graphics libraries derive from
Adafruit GFX graphics core Arduino library, this is the 'core' class that all our other graphics libraries derive from - GitHub - adafruit/Adafruit-GFX-...

大まかな流れはこんな感じ.フォントをインクルードした後に,setFont でインクルードしたフォントを指定すればいいだけ.

#include "Fonts/FreeSans12pt7b.h"    // 使いたいフォントをインクルード

Adafruit_8x16matrix matrixL = Adafruit_8x16matrix();
matrixL.begin(0x70);                 // 初期化
matrixL.setFont(&FreeSans12pt7b);    // フォント設定

matrixL.clear();                     // 画面クリア
matrixL.setCursor(0, 0);             // カーソル移動
matrixL.print("ABCabc123.!@");       // 表示する文字列を設定
matrixL.writeDisplay();              // 表示

フォントの比較

フォント確認用コードを用意した.GFX が用意している 16 種類のフォントとデフォルトフォント(フォントを指定しない)の合計 17 種類のフォントを比較してみる.

フォントによっては画面の外で描画されてしまって,何も表示されていないように見えたり,一部分しか表示されていないように見えたりする.フォントごとにいい感じの位置を調整してあげる必要があるので注意.

/*
** MIT License
** 
** Copyright (c) 2023 HeavyMoon
** 
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
** 
** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software.
** 
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
** SOFTWARE.
*/

#include "M5Atom.h"

#include "Adafruit_LEDBackpack.h"

#include "Fonts/FreeMono9pt7b.h"
#include "Fonts/FreeMonoBold9pt7b.h"
#include "Fonts/FreeMonoBoldOblique9pt7b.h"
#include "Fonts/FreeMonoOblique9pt7b.h"

#include "Fonts/FreeSans9pt7b.h"
#include "Fonts/FreeSansBold9pt7b.h"
#include "Fonts/FreeSansBoldOblique9pt7b.h"
#include "Fonts/FreeSansOblique9pt7b.h"

#include "Fonts/FreeSerif9pt7b.h"
#include "Fonts/FreeSerifBold9pt7b.h"
#include "Fonts/FreeSerifBoldItalic9pt7b.h"
#include "Fonts/FreeSerifItalic9pt7b.h"

#include "Fonts/Org_01.h"
#include "Fonts/Picopixel.h"
#include "Fonts/Tiny3x3a2pt7b.h"
#include "Fonts/TomThumb.h"

Adafruit_8x16matrix matrixL = Adafruit_8x16matrix();
Adafruit_8x16matrix matrixR = Adafruit_8x16matrix();

void setup() {
  M5.begin(true, true, true);
  // bool SerialEnable, bool I2CEnable, bool DisplayEnable
  // Default Serial Rate = 115200
  delay(10);

  matrixL.begin(0x70);
  matrixL.setBrightness(0x01);
  matrixL.setRotation(1);
  matrixL.setTextSize(1);
  matrixL.setTextWrap(false);
  matrixL.setTextColor(LED_ON);

  matrixR.begin(0x71);
  matrixR.setBrightness(0x01);
  matrixR.setRotation(1);
  matrixR.setTextSize(1);
  matrixR.setTextWrap(false);
  matrixR.setTextColor(LED_ON); 
}

uint8_t fonttype = 0;

void loop() {
  if (M5.Btn.wasPressed()) {
    Serial.println(fonttype);
    switch(fonttype){
      case 0:
        Serial.println("Font: Default");
        matrixL.setCursor(0, 6);
        matrixL.setFont();
        matrixR.setCursor(-16, 6);
        matrixR.setFont();
        break;


      case 1:
        Serial.println("Font: FreeMono9pt7b");
        matrixL.setCursor(0, 0);
        matrixL.setFont(&FreeMono9pt7b);
        matrixR.setCursor(-16, 0);
        matrixR.setFont(&FreeMono9pt7b);
        break;

      case 2:
        Serial.println("Font: FreeMonoBold9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeMonoBold9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeMonoBold9pt7b);
        break;

      case 3:
        Serial.println("Font: FreeMonoBoldOblique9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeMonoBoldOblique9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeMonoBoldOblique9pt7b);
        break;

      case 4:
        Serial.println("Font: FreeMonoOblique9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeMonoOblique9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeMonoOblique9pt7b);
        break;


      case 5:
        Serial.println("Font: FreeSans9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSans9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSans9pt7b);
        break;

      case 6:
        Serial.println("Font: FreeSansBold9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSansBold9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSansBold9pt7b);
        break;

      case 7:
        Serial.println("Font: FreeSansBoldOblique9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSansBoldOblique9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSansBoldOblique9pt7b);
        break;

      case 8:
        Serial.println("Font: FreeSansOblique9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSansOblique9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSansOblique9pt7b);
        break;


      case 9:
        Serial.println("Font: FreeSerif9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSerif9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSerif9pt7b);
        break;

      case 10:
        Serial.println("Font: FreeSerifBold9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSerifBold9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSerifBold9pt7b);
        break;

      case 11:
        Serial.println("Font: FreeSerifBoldItalic9pt7b");
        matrixL.setCursor(0, 5);
        matrixL.setFont(&FreeSerifBoldItalic9pt7b);
        matrixR.setCursor(-16, 5);
        matrixR.setFont(&FreeSerifBoldItalic9pt7b);
        break;

      case 12:
        Serial.println("Font: FreeSerifItalic9pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&FreeSerifItalic9pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&FreeSerifItalic9pt7b);
        break;


      case 13:
        Serial.println("Font: Org_01");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&Org_01);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&Org_01);
        break;

      case 14:
        Serial.println("Font: Picopixel");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&Picopixel);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&Picopixel);
        break;

      case 15:
        Serial.println("Font: Tiny3x3a2pt7b");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&Tiny3x3a2pt7b);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&Tiny3x3a2pt7b);
        break;

      case 16:
        Serial.println("Font: TomThumb");
        matrixL.setCursor(0, 6);
        matrixL.setFont(&TomThumb);
        matrixR.setCursor(-16, 6);
        matrixR.setFont(&TomThumb);
        break;

      default:
        Serial.println("Font: Default");
        matrixL.setCursor(0, 0);
        matrixL.setFont();
        matrixR.setCursor(-16, 0);
        matrixR.setFont();
        break;
    };

    matrixL.clear();
    matrixL.print("ABCabc123.!@");
    matrixL.writeDisplay();

    matrixR.clear();
    matrixR.print("ABCabc123.!@");
    matrixR.writeDisplay();

    fonttype = ++fonttype % 17;
  }

  M5.update();
}

Default

1文字あたり 5×7 で構成されている.

5文字しか表示できない.テキストだけで情報量を稼ぐとなると,文字を流すなどの工夫が必要.

FreeMono9pt7b

用意されているフォントの内,比較的小さい 9pt のフォントでも画面からはみ出てしまう.

FreeMonoBold9pt7b

FreeMonoBoldOblique9pt7b

FreeMonoOblique9pt7b

FreeSans9pt7b

FreeSansBold9pt7b

FreeSansBoldOblique9pt7b

FreeSansOblique9pt7b

FreeSerif9pt7b

FreeSerifBold9pt7b

FreeSerifBoldItalic9pt7b

FreeSerifItalic9pt7b

Org_01

1文字あたり 5×5 で構成されている.デフォルトの文字よりも縦方向にドット2つ分コンパクトになっているが,横幅は変わらないので一度に表示できる文字数は変わらない.デフォルトよりも若干余白があるので,インジケータとかに活用できるかもしれない.

Picopixel

1文字あたり 3×5 で構成されている.横幅がコンパクトな分,一度に8文字くらい表示できる.

Tiny3x3a2pt7b

1文字あたり 3×3 で構成されている.縦方向がかなりコンパクトな分,2行にすれば18文字表示できる.が,やや可読性に難あり.遠目で見ればそれぞれの文字の特徴を的確に捉えた味のある文字に見えなくもない.昔のゲームのドット絵に通じるものを感じる気がする.

TomThumb

1文字あたり 3×5 で構成されている.若干の違いはあるものの,概ね Picopixel と同じ.

おわりに

自分でフォントのビットマップ用意するか考えてたけど,結構簡単にいろいろなフォント使えてしまった.

8×32 のマトリクスだと Picopixel か TomThumb あたりが使い勝手良さそう.もう少し攻めるなら Tiny3x3a2pt7b もありだが可読性は怪しい.

ttf ファイルから自作フォントを用意する話は気が向いたら書く.たぶん.

コメント

タイトルとURLをコピーしました