🈂️
Skia-python でカスタムフォント描画するメモ
背景
テキストをより任意に描画したい...
Whisper とかでの音声認識で, 音素位置に音素や文字描画したいとか, 文字単位で大きさ変えたり色変えたりとか...
とりあえずは python 環境で...
Skia-python でフォント描画してみます!
Setup
Linux だと OpenGL/Mesa 環境がいります.
Swiftshader 使えば CPU 描画いけそうなきもするが...
とりあえずは OpenGL/Mesa 環境を想定します.
Font
カスタムのフォントファイルを使いたい場合,
MakeFromFile でいけます.
今回は「ぼくたちのゴシック」使ってみました.
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