テキストの基本的な描画方法については、「Skiaの基本:テキスト描画の基本」で説明しました。
ここでは、もうすこし実践的なテキスト描画のテクニックについて説明します。
折り返しテキストの描画
長いテキストを、指定した幅で折り返して描画する・・・ような便利なメソッドは、Skiaには用意されていません。代わりに、SKFont.BreakTextメソッドを利用して、自前で折り返し処理を実装する必要があります。
SKFont.BreakTextメソッドは、文字列の先頭から、指定した幅に収まる最大の文字数を返します。これを利用して、テキストを1行ごとに分割しながら描画していきます。
以下のコードは、指定した幅で折り返しながらテキストを描画する簡単な例です。なお、改行コードには対応していません。
// テキストのためのペイント
using var paint = new SKPaint {
IsAntialias = true,
Color = SKColors.Black
};
// フォントを作成
using var typeface = SKTypeface.FromFamilyName( "Yu Gothic UI" );
using var font = new SKFont( typeface, 20 );
// 描画するテキスト
string text = "吾輩は猫かもしれないし、猫じゃないかもしれない。そもそも猫とはなんだろう。これは形而上学的な問題である。";
// テキストの位置と幅
int x = 40;
int y = 40;
int width = 220;
// テキストを折り返して描画
int lenText = text.Length;
while ( lenText > 0 ) {
// 1行分のテキストを取得
int lenLine = font.BreakText( text, width );
string line = text.Substring( 0, lenLine );
// 1行分を描画
canvas.DrawText( line, x, y, font, paint );
// 次の行へ
y += (int)( font.Metrics.CapHeight + 8 );
text = text.Substring( lenLine );
lenText -= lenLine;
}
SKFont.BreakTextメソッドは、欧米言語の単語区切りは考慮されませんが、なぜか日本語の句読点での禁則処理は考慮してくれるため、自然な折り返しが実現できます。
実行すると、以下のように、指定した幅で折り返しながらテキストが描画されます。禁則処理が正しく行われている点に注目してください。
段落テキストの描画
Skiaには、Flutter等でも利用されているParagraphという段落テキストを扱うためのクラスがある・・・のですが、残念ながら、SkiaSharpでのサポートに関しては開発チームが消極的で、現時点では、利用できる見通しが立っていません。諦めましょう。
代わりに、かなりオーバースペックですが、Topten.RichTextKitというサードパーティ製のライブラリを利用することが推奨されています。
以下のコードは、RichTextKitを利用して、段落テキストを描画する例です。スタイルによる文字の装飾や、改行コードの処理もサポートされています。
// RichTextKitのTextBlock(描画領域の定義)を作成
var tb = new TextBlock();
// 最大幅を設定
tb.MaxWidth = 220;
// テキストの配置を左揃えに設定
tb.Alignment = TextAlignment.Left;
// 文字のスタイルを作成
var styleNormal = new Style() {
FontFamily = "Yu Gothic UI",
FontSize = 20
};
var styleBold = new Style() {
FontFamily = "Yu Gothic UI",
FontSize = 20,
FontWeight = 800
};
// スタイルを指定してテキストを追加
string title = "吾輩は猫なのか?";
tb.AddText( title + "\n", styleBold );
string text = "吾輩は猫かもしれないし、猫じゃないかもしれない。\nそもそも猫とはなんだろう。\nこれは形而上学的な問題である。";
tb.AddText( text, styleNormal );
// 描画
tb.Paint( canvas, new SKPoint( 40, 20 ) );
実行すると、以下のように、段落テキストが描画されます。文字の装飾や改行も簡単に扱うことができました。
曲がったテキストの描画
Skiaでは、パスに沿ってテキストを描画することも可能です。これにより、曲線や円形など、様々な形状に沿ったテキストの表現が可能になります。
// テキストのためのペイント
using var paint = new SKPaint {
IsAntialias = true,
Color = SKColors.Black
};
// フォントを作成
using var typeface = SKTypeface.FromFamilyName( "Yu Gothic UI" );
using var font = new SKFont( typeface, 24 );
// テキストを配置するパスを作成
using var path = new SKPath();
path.MoveTo( 50, 110 );
path.CubicTo( 100, 60, 200, 170, 250, 110 );
// テキストを描画
string text = "吾輩は猫かもしれない";
canvas.DrawTextOnPath( text, path, 0, 0, font, paint );
実行すると、以下のように、ベジェ曲線上にテキストが描画されます。
パフォーマンスチューニング
テキスト描画のパフォーマンスを向上させるために、いくつかのポイントがあります。
フォントのキャッシュ
頻繁に使用するフォントは、SKFontオブジェクトを再利用することで、フォントのロード時間を削減できます。可能な限り、同じフォントを使い回すようにしましょう。
テキストのキャッシュ
同じテキストを何度も描画する場合は、テキストを事前に描画しておき、その結果を再利用することで、描画処理を効率化できます。具体的には、SKImageやSKBitmapとしてテキストをキャッシュし、必要に応じてそれを描画する方法です。
TextBlobの利用
静的なテキストを繰り返し描画する場合は、SKTextBlobを利用することで、描画処理を効率化できます。
SKTextBlobは、フォントの字形(グリフ)と位置情報をまとめた、テキスト描画をキャッシュするためのオブジェクトです。一度作ったSKTextBlobを使い回すことで、同じテキストの描画を高速化できます。以下にその簡単な例を示します。
// テキストのためのペイント
using var paint = new SKPaint {
IsAntialias = true,
Color = SKColors.Black
};
// フォントを作成
using var typeface = SKTypeface.FromFamilyName( "Yu Gothic UI" );
using var font = new SKFont( typeface, 24 );
// TextBlobを作成
string text = "吾輩は猫かもしれない";
using var blob = SKTextBlob.Create( text, font );
// TextBlobを描画
canvas.DrawText( blob, 50, 100, paint );
このblobを使い回すことで、フォントの字形の検索や、レイアウトの計算を省略できるため、同じテキストの描画が高速化されます。ゲームのUI表示など、毎フレーム同じテキストを描画するような場合に、特に効果的です。
Topten.RichTextKitを使っている場合
RichTextKitを利用している場合は、TextBlockオブジェクトを再利用することで、パフォーマンスを向上させることができます。TextBlockは、テキストのレイアウト情報をキャッシュするため、同じ内容のテキストを繰り返し描画する場合に効果的です。
品質チューニング
SKFontには、フォントのレンダリングを調整するための、EdgingとHintingという2つのプロパティがあります。それぞれ、表示デバイスや用途に応じて、適切な設定を選択することで、見やすさやパフォーマンスを最適化することができます。
Edging
Edgingプロパティは、アンチエイリアスの方法を指定します。以下の3つのモードがあります。
| モード | 説明 |
|---|---|
Alias |
アンチエイリアスを無効にします。 |
Antialias |
標準的なアンチエイリアスを適用します。(デフォルト) |
SubpixelAntialias |
サブピクセルアンチエイリアスを適用します。 |
SubpixelAntialiasは、LCDディスプレイの赤、青、緑のサブピクセルの構造を利用して、より滑らかな描画を実現する方法なのですが、最近のバージョンのSkiaではサポートされていないようです。
実際にAliasとAntialiasで描画した例を示します。
Hinting
Hintingプロパティは、小さな文字を描画する際に、ピクセルグリッドに文字を合わせて見やすくするための設定です。以下の4つのモードがあります。
| モード | 説明 |
|---|---|
None |
ヒンティングを無効にします。 |
Slight |
軽度のヒンティングを適用します。 |
Normal |
通常のヒンティングを適用します。(デフォルト) |
Full |
強力なヒンティングを適用します。 |
ほとんどの場合、NoneとNormal以外の差はあまり感じられません。
実際にNoneとNormalで描画した例を示します。
まとめ
Skiaには、さまざまなテキスト描画のテクニックが用意されています。ただ、標準機能だけでは対応できないケースも多いため、サードパーティ製のライブラリを活用することも検討しましょう。
総合目次




