LovyanGFXで画面描画(11):内蔵以外の日本語フォントを使用して高速道路っぽい表示を作る

LovyanGFX Advent Calendar 2022 22日目
「LovyanGFXで画面描画(10):内蔵以外のフォントを使用してデジタル時計を作る」
では TrueType フォントを取り込んで描画しましたが、日本語フォントはこのやりかたではできません。

 LovyanGFX の内蔵日本語フォントは、
https://github.com/tanakamasayuki/u8g2_font_ilfont
https://github.com/tanakamasayuki/efont
を取り込んだものだそうです。

このうち、IPA / IPAex フォントについては、tanakamasayuki さんの「LovyanGFX入門 その3 日本語フォント描画系 | Lang-ship」
https://lang-ship.com/blog/work/lovyangfx-3-ja-font/
で解説されています。

tanakamasayuki さんと同様のやりかたで、日本語 TrueType フォントを取り込んでみます。

# 環境

- Ubuntu 22.04 LTS Ja
- LovyanGFX for PC

# GD-高速道路ゴシックJA フォント

https://forest.watch.impress.co.jp/library/software/gdhighway/
こちらから、GDHighwayGoJA-Rev108b-TTF.zip をダウンロードし、解凍します。

```
$ unzip GDHighwayGoJA-Rev108b-TTF.zip 
Archive:  GDHighwayGoJA-Rev108b-TTF.zip
  inflating: GDHighwayGoJA-Rev108b-TTF/GDhwGoJA-TTF108b.ttf  
  inflating: GDHighwayGoJA-Rev108b-TTF/readme.txt  
$ cd GDHighwayGoJA-Rev108b-TTF/
$ ls
GDhwGoJA-TTF108b.ttf  readme.txt

```
# ツールを用意する

事前に必要なのは以下の3つです。

- otf2bdf
- bdfconv
- mapファイル

## otf2bdf 

ubuntu パッケージを利用します。

```
$ sudo apt install otf2bdf
```

## bdfconv

u8g2 レポジトリに含まれています。レポジトリをクローンします。

```
$ git clone https://github.com/olikraus/u8g2.git
```
167MBytes ありました。

```
$ cd u8g2/tools/font/bdfconv
$ ls
Makefile   bdf_font.c  bdf_glyph.c  bdf_kern.c  bdf_parser.c  bdf_tga.c    bdfconv_2_22.exe              fd.c  main.c
bdf_8x8.c  bdf_font.h  bdf_glyph.h  bdf_map.c   bdf_rle.c     bdfconv.exe  create_mingw_bdfconv_exe.bat  fd.h  test_helvb18.bat
```
makefile ありますね。念のため make clean して
```
$ make clean
rm main.o bdf_font.o bdf_glyph.o bdf_parser.o bdf_map.o bdf_rle.o bdf_tga.o fd.o bdf_8x8.o bdf_kern.o main.s bdf_font.s bdf_glyph.s bdf_parser.s bdf_map.s bdf_rle.s bdf_tga.s fd.s bdf_8x8.s bdf_kern.s bdfconv
rm: 'main.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_font.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_glyph.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_parser.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_map.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_rle.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_tga.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'fd.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_8x8.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_kern.o' を削除できません: そのようなファイルやディレクトリはありません
rm: 'main.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_font.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_glyph.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_parser.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_map.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_rle.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_tga.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'fd.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_8x8.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdf_kern.s' を削除できません: そのようなファイルやディレクトリはありません
rm: 'bdfconv' を削除できません: そのようなファイルやディレクトリはありません
make: [Makefile:20: clean] エラー 1 (無視されました)
```
make します。
```
$ make
$ ls
Makefile   bdf_font.c  bdf_glyph.c  bdf_kern.c  bdf_map.o     bdf_parser.s  bdf_tga.c  bdfconv.exe                   fd.h    main.o
bdf_8x8.c  bdf_font.h  bdf_glyph.h  bdf_kern.o  bdf_map.s     bdf_rle.c     bdf_tga.o  bdfconv_2_22.exe              fd.o    main.s
bdf_8x8.o  bdf_font.o  bdf_glyph.o  bdf_kern.s  bdf_parser.c  bdf_rle.o     bdf_tga.s  create_mingw_bdfconv_exe.bat  fd.s    test_helvb18.bat
bdf_8x8.s  bdf_font.s  bdf_glyph.s  bdf_map.c   bdf_parser.o  bdf_rle.s     bdfconv    fd.c                          main.c
```

bdfconv ができています。
```
$ ./bdfconv
bdfconv [options] filename
-h          Display this help
-v          Print log messages
-b <n>      Font build mode, 0: proportional, 1: common height, 2: monospace, 3: multiple of 8, 4: 5x7 mode
-f <n>      Font format, 0: ucglib font, 1: u8g2 font, 2: u8g2 uncompressed 8x8 font (enforces -b 3)
-m 'map'    Unicode ASCII mapping
-M 'mapfile'    Read Unicode ASCII mapping from file 'mapname'
-o <file>   C output font file
-k <file>   C output file with kerning information
-p <%>      Minimum distance for kerning in percent of the global char width (lower values: Smaller gaps, more data)
-x <n>      X-Offset for 8x8 font sub-glyph extraction (requires -f 2, default 0)
-y <n>      Y-Offset for 8x8 font sub-glyph extraction (requires -f 2, default 0)
-th <n>     Horizontal size of the 8x8 glyphs (requires -f 2, default 1)
-tv <n>     Vertical size of the 8x8 glyphs (requires -f 2, default 1)
-n <name>   C indentifier (font name)
-d <file>   Overview picture: Enable generation of bdf.tga and assign BDF font <file> for description
-l <margin> Overview picture: Set left margin
-g <glyphs> Overview picture: Set glyphs per line (default: 16)
-a          Overview picture: Additional font information (background, orange&blue dot)
-t          Overview picture: Test string (Woven silk pyjamas exchanged for blue quartz.)
-r          Runtime test

map := <mapcmd> { "," <mapcmd> }
mapcmd := <default> | <maprange> | <exclude> | <exclude-kerning>
default := "*"
maprange := <range> [  ">" <addexpr> ]        Move specified glyph <range> to target code <num>
exclude := "~" <range> 
exclude-kerning:= "x" <range> 
range := <addexpr> [ "-" <addexpr> ]          Select glyphs within specified range
addexpr := <mulexpr> [ "+" <mulexpr> ]
mulexpr := <num> [ "*" <num> ]
num := <hexnum> | <decnum>
hexnum := "$" <hexdigit> { <hexdigit> }
decnum := <decdigit> { <decdigit> }
decdigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
hexdigit := "a" | "b" | "c" | "d" | "e" | "f" | "A" | "B" | "C" | "D" | "E" | "F" | <decdigit>
{ } zero, one ore more, [ ] zero or once, | alternative
example:
  -m '32-255'     select gylphs from encoding 32 to 255
  -m '32-255,~64' select gylphs from encoding 32 to 255, exclude '@'
  -m '32,48-57'   select space, '1', '2', ... '9'
build modes:
 -b 0: Most compact, glyph bitmap is minimal
 -b 1: Like -b 0, but glyph bitmap is extended to the height of the largest glyph within the selected glyph list.
       Also the width of the gylphs is extended to cover the delta x advance.
 -b 2: Like -b 1, but glyph width is set to the width of the largest glyph within the selected gylph list.
 -b 3: Like -b 2, but width and height are forced to be a multiple of 8.


```

結構細かいところまで指定ができますね。

## map ファイル

Unicode のコード空間は膨大です。その中のどの文字をフォントファイルに含めるかを決めるファイルです。
日本語に対応したものとして、
https://raw.githubusercontent.com/olikraus/u8g2/master/tools/font/build/japanese3.map
こちらから、japanese3.map をダウンロードします。


# フォントファイルの作成

今回は、フォントファイルがあるディレクトリで操作しました。

24ポイントを作ってみます。
```
$ otf2bdf -r 72 -p 24 -o GDhwGoJA-TTF108b_24pt.bdf GDhwGoJA-TTF108b.ttf 
$ ls
GDhwGoJA-TTF108b.ttf  GDhwGoJA-TTF108b_24pt.bdf  readme.txt
```
bdf ファイルができたので Cソースにします。

```
$ ../u8g2/tools/font/bdfconv/bdfconv -v -b 0 -f 1 -M ../japanese3.map GDhwGoJA-TTF108b_24pt.bdf -o GDhwGoJA-TTF108b_24pt.c
Parse File GDhwGoJA-TTF108b_24pt.bdf: 14963 glyph(s) found
Map: exclude=0 from=32/$20 to=127/$7f map=32/$20
Map: exclude=0 from=12288/$3000 to=12288/$3000 map=12288/$3000 (further single glyph logs disabled)
Reduce: Start
Reduce: End
CalculateMaxBBX: x=-1, y=-9, w=29, h=31
CalculateMaxBBX: Encodings x=106, y=103, w=65335, h=36
bf_CalculateMinMaxDWidth: dx_min=5, dx_max=29
bf_CalculateMinMaxDWidth: x_min=-1, x_max=15
bf_CalculateMaxBitFieldSize: bbx.x=5, bbx.y=6, bbx.w=5, bbx.h=5, dwidth=6
RLE Compress: best zero bits 4, one bits 4, total bit size 888512
RLE Compress: Font code generation, selected glyphs=3857, total glyphs=14963
RLE Compress: ASCII gylphs=95, Unicode glyphs=3762
RLE Compress: Glyphs per unicode lookup table entry=101
RLE Compress: Unicode lookup table len=37, written entries=37
RLE Compress: Unicode lookup table first entry: delta=148, encoding=12412
RLE Compress: Unicode lookup table last entry: delta=2755, encoding=65535
RLE Compress: Unicode glyphs written=3762
RLE Compress: 'A' pos = 888, 'a' pos = 1846
RLE Compress: Font size 111239
bf_WriteU8G2CByFilename: Write file 'GDhwGoJA-TTF108b_24pt.c'
```

中身は以下のようになってました。

```

/*
  Fontname: -FreeType-GD HighwayGothicJA TTF-Medium-R-Normal--24-240-72-72-P-31-ISO10646-1
  Copyright: (C) GroupD.B.P.'s / pumpCurry
  Glyphs: 3857/14963
  BBX Build Mode: 0
*/
#ifdef U8G2_USE_LARGE_FONTS
const uint8_t bdf_font[111239] U8G2_FONT_SECTION("bdf_font") = 
  "\21\0\4\4\5\5\5\6\6\35\37\377\367\24\367\25\376\3x\7\66\12\63 \6\0@\360\5!\11\343"
  "N/\205\37\30c\42\12\7E\66\205!\365\23\1#\62\315J\17&\61\243\304\214\22#j\214\250\61"
  "\242\306\10y\360 \311\30QcD\215\21\363\340A\212\61\242\306\210\22$J\314(\61\243\304\210\32#"

.
.
.  "\13\320P\363\206\17\204\313\1\377\343\11W@\371\206\37\4\377\344\13\342n\17\207\7C\37\14\377\345("
  "\362N\357\6\242$\10\22!H\206\30!b\244\10\21#D\216\10\251#(\260Bk\330\334\3\21\17"
  "\304\21\247\337\1\0";
#endif /* U8G2_USE_LARGE_FONTS */
```

# LovyanGFX で使う

先の C ファイルをスケッチのディレクトリにコピーします。

Cファイルを以下のように変更

冒頭部分：

```
#ifdef U8G2_USE_LARGE_FONTS
const uint8_t bdf_font[111239] U8G2_FONT_SECTION("bdf_font") = 
```
↓
```
#define LGFX_USE_V1
#include <LovyanGFX.hpp>

const uint8_t myFont_data[111239] = 
```

末尾部分：
```
#endif /* U8G2_USE_LARGE_FONTS */
```
↓
```
extern const lgfx::U8g2font myFont = { myFont_data };
```

名前などは
「LovyanGFXで画面描画(9):日本語フォントのうち必要なシェイプのみをデータ化」
https://qiita.com/nanbuwks/items/e09abbb90cedd93a2118
で紹介したやまねこ氏の日本語フォントサブセットジェネレータに習ってみました。



このようにして、スケッチ側では
```
 extern const lgfx::U8g2font myFont;
```

として使うことになります。



# スケッチ


以下のようにしてみました。

```

#define LGFX_USE_V1
#include "arduinolib_for_PC.hpp"
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>
#include "Segment16C_Bold_Italic_24P.h"

#include <time.h> // for PC
static LGFX display ( 200,200,1 );
static LGFX_Sprite sprite(&display);
 extern const lgfx::U8g2font myFont;

void setup() {
  display.init();
  display.setSwapBytes(true); 
  sprite.createSprite(256,256);
}

void loop(){
  struct tm *newtime;
  time_t ltime;
  time(&ltime);
  newtime = localtime(&ltime);
  sprite.clear();
  sprite.fillRect(0,0,200,200,display.color888(0,100,0));
  sprite.setTextSize(1);
  sprite.setFont(&myFont);
  sprite.setTextColor(display.color888(240,247,247));
  sprite.setCursor(20,10);
  sprite.printf(" %02d:%02d:%02d\n\n",
        newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
  sprite.println("東名 高速道路");
  sprite.println("↑三鷹料金所5km");
  sprite.println("←出口 500m");
  sprite.pushSprite(0,0);
  delay(1000);
}



```
実行結果


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/57e08c39-c3f0-872d-3fa8-fcc12ea58579.png)

矢印文字が化けてますね。