ラスター画像フォントを作ってターミナルで表示する実験（その1）

端末にミスキーのカスタム絵文字を表示したくてラスター画像フォントを作るのが一番かなと思って実験してみました。

```sh
pip install fonttools
wget https://s3.arkjp.net/misskey/806660c1-09cf-4e17-8025-fbc3cf9aed0c.png
```

```python
from fontTools.ttLib import TTFont
from fontTools.fontBuilder import FontBuilder
from fontTools.ttLib.ttFont import newTable
from fontTools.ttLib.tables._s_b_i_x import table__s_b_i_x
from fontTools.ttLib.tables import sbixGlyph, sbixStrike
from fontTools.pens.t2CharStringPen import T2CharStringPen

fb = FontBuilder(unitsPerEm = 1000, isTTF=False)
fb.setupGlyphOrder([".notdef", ".null", ".CR", ":mi_:"])
fb.setupCharacterMap({0x10FFFF: ":mi_:"})
advanceWidths = {".notdef": 1000, ".null": 0, ".CR": 0, ":mi_:": 1000} #

familyName = "MisskeyCustomEmojiFont"
styleName = "Monospace"
version = "0.1"

nameStrings = dict(
    familyName=dict(en=familyName, ja="ミスキーカスタム絵文字フォント"),
    styleName=dict(en=styleName, ja="Mono"),
    uniqueFontIdentifier="fontBuilder: " + familyName + "." + styleName,
    fullName=familyName + "-" + styleName,
    psName=familyName + "-" + styleName,
    version="Version " + version,
)


# Create an sbix table
sbix = newTable("sibx")
sbix_table = table__s_b_i_x()

glyphs = [".notdef", ".null", ".CR", ":mi_:"]

#ppem = 12
ppem = 256
sbix_strike = sbixStrike.Strike(ppem=ppem, resolution=72)

for glyph_name, image_path in zip(glyphs, ["806660c1-09cf-4e17-8025-fbc3cf9aed0c.png", "806660c1-09cf-4e17-8025-fbc3cf9aed0c.png",
                                           "806660c1-09cf-4e17-8025-fbc3cf9aed0c.png", "806660c1-09cf-4e17-8025-fbc3cf9aed0c.png"]):
    with open(image_path, "rb") as image_file:
        image_data = image_file.read()

        sbix_glyph = sbixGlyph.Glyph(glyphName=glyph_name, graphicType="png ", imageData=image_data) # referenceGlyphName=glyph_name,
        sbix_strike.glyphs[glyph_name] = sbix_glyph

sbix_table.numStrikes += 1
sbix_table.strikes[ppem] = sbix_strike

fb.font["sbix"] = sbix_table


pen = T2CharStringPen(1000, None)
pen.moveTo((0, 0))
pen.lineTo((0, 1000))
pen.lineTo((1000, 1000))
pen.lineTo((1000, 0))
pen.closePath()

charString = pen.getCharString()
charStrings = {
    ".notdef": charString,
    ".null": charString,
    ".CR": charString,
    ":mi_:": charString,}


fb.setupCFF(nameStrings["psName"], {"FullName": nameStrings["psName"]}, charStrings, {})
lsb = {gn: cs.calcBounds(None)[0] for gn, cs in charStrings.items()}
lsb2 = {gn: cs.calcBounds(None)[1] for gn, cs in charStrings.items()}

h_metrics = {}
for gn, advanceWidth in advanceWidths.items():
#    metrics[gn] = (0, 0)
#    h_metrics[gn] = (advanceWidth, lsb[gn])
    h_metrics[gn] = (advanceWidth, 0)
fb.setupHorizontalMetrics(h_metrics)

v_metrics = {}
for gn, advanceWidth in advanceWidths.items():
#    v_metrics[gn] = (1000, lsb2[gn])
    v_metrics[gn] = (1000, 0)
fb.setupVerticalMetrics(v_metrics)

fb.setupHorizontalHeader(ascent=1000, descent=0) # ascent=824, descent=200
fb.setupVerticalHeader(ascent=1000, descent=0) # ascent=824, descent=200
fb.setupNameTable(nameStrings)
fb.setupOS2(sTypoAscender=1000, sTypoDescender=0, usWinAscent=1000, usWinDescent=0)
fb.setupPost()
#fb.setupDummyDSIG()

font_path = "./my_font.otf"
# Save the font to a file
fb.save(font_path)

import os
os.system("cp %s ~/.local/share/fonts/" % font_path)
os.system("fc-cache -f")
```
端末の再起動が必要かも？

```sh|
$ python -c "print('\U0010FFFF')"
```
![mi_terminal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109174/fd83a944-bc8a-9773-57b7-578e7da72434.png)


# 続き
https://qiita.com/vipper36/items/2dd7fcda17a51701dad0