🈂️

Skia-python でカスタムフォント描画するメモ

2023/04/21に公開

背景

テキストをより任意に描画したい...
Whisper とかでの音声認識で, 音素位置に音素や文字描画したいとか, 文字単位で大きさ変えたり色変えたりとか...

とりあえずは python 環境で...
Skia-python でフォント描画してみます!

https://github.com/kyamagu/skia-python

Setup

Linux だと OpenGL/Mesa 環境がいります.
Swiftshader 使えば CPU 描画いけそうなきもするが...

https://qiita.com/syoyo/items/ef5518f8c3638e50a6b9

とりあえずは OpenGL/Mesa 環境を想定します.

Font

https://github.com/kyamagu/skia-python/blob/main/notebooks/Drawing-Texts.ipynb

カスタムのフォントファイルを使いたい場合,

https://github.com/kyamagu/skia-python/issues/143

MakeFromFile でいけます.

https://fontopo.com/?p=164

今回は「ぼくたちのゴシック」使ってみました.

def draw_font(text, font):

    width = 512
    height = 512

    surface = skia.Surface(width, height)
    canvas = surface.getCanvas()

    paint = skia.Paint(AntiAlias=True, Color=skia.ColorRED)
    canvas.drawString(text, 10, 30, font, paint)

    image = surface.makeImageSnapshot()

    # image.toarray() で numpy 配列取得



typeface = skia.Typeface.MakeFromFile("bokutachi.otf")
font = skia.Font(typeface, 28)

img = draw_font("こんにちは", font)

Streamlit と組み合わせ

とりあえずは Skia のを画像データにして, st.image で描画でしょうか.
インタラクティブにしたい場合はなにかほかの手を考える必要があるかも.

import streamlit as st
import skia

st.title("Streamlit + Skia")

def draw_font(text, font):

    width = 700
    height = 512

    surface = skia.Surface(width, height)
    canvas = surface.getCanvas()

    paint = skia.Paint(AntiAlias=True, Color=skia.ColorRED)
    canvas.drawString(text, 10, 30, font, paint)

    image = surface.makeImageSnapshot()

    return image.toarray()



typeface = skia.Typeface.MakeFromFile("bokutachi.otf")
font = skia.Font(typeface, 28)

img = draw_font("少しあどけない、サンセリフの日本語フォントです", font)
st.image(img)

Voila!

drawString だと (0, 0) だと canvas からはみ出るのか, いくらか y offset をかけてあげる必要があるようです.

TODO

  • Canvas の大きさに合わせて Text wrap うまくやる
  • streamlit で st.image で描画の場合, HDPI だとぼやけるのでなにかうまい対応策を考える(st.image に描画時スケーリングするオプションがあるといいのだが...)
    • st.image は SVG も受け取れるので, Skia で SVG 出力するのがいいか?
    • ただ筆者環境では skia SVGCanvas つくるとセグフォする...
  • Linux の場合, Swiftshader あたりで CPU only(e.g. GPU 無いサーバで動かすなど)でいけるか調べる

Discussion