Introduction

System.Drawing といえば、 WinForms の時代からお世話になっている馴染みのある名前空間だ。
SoftwareBitmap? 知らんなぁ。

.NET 6 になってから、System.Drawing.Common が Windows でしかサポートされない のように警告が出るようになったが、System.Drawing はロックの問題を除けば今でも最高のパフォーマンスを叩き出してくれる。

とはいえ、そろそろ次の API について学習しないと取り残されるのは明白。
少なくとも、 MAUI では System.Drawing は使えないわけで。

というわけで、良く取り上げられる SkiaSharp を使ってみることにした。

なお、性能については下記を参照。

How to use

幸いなことに、使ってみると System.Drawing と似た設計の API であることに気づく。

思った機能を実現するための API が見つからないストレスは、コンポーネント移行の宿命として諦めるとして、これは嬉しい。

具体的な対応は下記。
最低限、これだけわかっていれば、大抵のケースはどうとでもなる。

クラス

System.Drawing SkiaSharp
System.Drawing.Bitmap SkiaSharp.SKBitmap
System.Drawing.Graphics SkiaSharp.SKCanvas
- SkiaSharp.SKPaint

SkPaint は 矩形を描画する際に使用する色などの情報を保持するクラスである。

System.Drawing では、DrawLine 等に直接色などを指定したが、SkiaSharp ではこの SKPaint に設定する。

下記の System.Drawing のソースは

1
2
using var bitmap = new System.Drawing.Bitmap(200, 200);
using var graphics = System.Drawing.Graphics.FromImage(bitmap);

下記の SkiaSharp のソースと意味的に同等である。

1
2
using var bitmap = new SkiaSharp.SKBitmap(200, 200);
using var canvas = new SkiaSharp.SKCanvas(bitmap);

メソッド/プロパティ

ファイルの読み書き

System.Drawing SkiaSharp 補足
System.Drawing.Bitmap.FromFile(string filename) SkiaSharp.SKBitmap.Decode(byte[] buffer) System.IO.File.ReadAllBytes(string path) でも使えば意味は同じ。
Stream を受け取るコンストラクタもあるので同等。
System.Drawing.Bitmap.Save(Stream stream, ImageFormat format) SkiaSharp.SKBitmap.Encode(Stream stream, SKEncodedImageFormat format) FileStream を指定すればファイルに、MemoryStream を指定すればメモリにエンコードされる

矩形の描画

System.Drawing SkiaSharp
System.Drawing.Graphics.DrawRectangle SkiaSharp.SKCanvas.DrawRect

下記の System.Drawing のソースは

1
2
3
using var bitmap = new System.Drawing.Bitmap(200, 200);
using var graphics = System.Drawing.Graphics.FromImage(bitmap);
graphics.DrawRectangle(System.Drawing.Pens.Red, new System.Drawing.Rectangle(x, y, width, right));

下記の SkiaSharp のソースと意味的に同等である。

1
2
3
4
5
6
using var paint = new SkiaSharp.SKPaint();
using var bitmap = new SkiaSharp.SKBitmap(200, 200);
using var canvas = new SkiaSharp.SKCanvas(bitmap);
paint.Color = new SkiaSharp.SKColor(255, 0, 0);
paint.Style = SkiaSharp.SKPaintStyle.Stroke;
skCanvas.DrawRect(new SkiaSharp.SKRect(left, top, right, bottom), paint);

文字の描画

System.Drawing SkiaSharp
System.Drawing.Graphics.DrawString SkiaSharp.SKCanvas.DrawText

下記の System.Drawing のソースは

1
2
3
4
using var bitmap = new System.Drawing.Bitmap(200, 200);
using var graphics = System.Drawing.Graphics.FromImage(bitmap);
using var font = new System.Drawing.Font("Calibri", 16);
graphics.DrawString("test", font, System.Drawing.Brushes.Red, x, y);

下記の SkiaSharp のソースと意味的に同等である。

1
2
3
4
5
6
7
8
using var paint = new SkiaSharp.SKPaint();
using var bitmap = new SkiaSharp.SKBitmap(200, 200);
using var canvas = new SkiaSharp.SKCanvas(bitmap);
using var font = SkiaSharp.SKTypeface.FromFamilyName("Calibri");
paint.Color = new SkiaSharp.SKColor(255, 0, 0);
paint.Typeface = font;
paint.TextSize = 16;
skCanvas.DrawText("test", x, y, paint);

文字のサイズ計測

そこまで利用することはないが…

System.Drawing SkiaSharp
System.Drawing.Graphics.MeasureString SkiaSharp.SKCanvas.MeasureText

下記の System.Drawing のソースは

1
2
3
4
using var bitmap = new System.Drawing.Bitmap(200, 200);
using var graphics = System.Drawing.Graphics.FromImage(bitmap);
using var font = new System.Drawing.Font("Calibri", 16);
System.Drawing.SizeF size = graphics.MeasureString("test", font);

下記の SkiaSharp のソースと意味的に同等である。

1
2
3
4
5
6
7
8
using var paint = new SkiaSharp.SKPaint();
using var bitmap = new SkiaSharp.SKBitmap(200, 200);
using var canvas = new SkiaSharp.SKCanvas(bitmap);
using var font = SkiaSharp.SKTypeface.FromFamilyName("Calibri");
paint.Typeface = font;
paint.TextSize = 16;
var textBounds = new SkiaSharp.SKRect();
skCanvas.MeasureText("test", ref textBounds);

取得できる値がサイズと矩形だが、おおよその意味は同じ。

ただし、矩形の左上座標は 0, 0 とは限らない点に注意。

ピクセルへのポインタ

画素値への高速アクセスにポインタは欠かせない。

System.Drawing SkiaSharp
System.Drawing.Imaging.BitmapData.Scan0 SkiaSharp.SKBitmap.GetPixels()

下記の System.Drawing のソースは

1
2
3
4
5
6
7
using var bitmap = new System.Drawing.Bitmap(200, 200);
using var graphics = System.Drawing.Graphics.FromImage(bitmap);
using var font = new System.Drawing.Font("Calibri", 16);
using var bitmap = new Bitmap(200, 200);
System.Drawing.Imaging.BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, 200, 200), System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
var poiner = data.Scan0;
bitmap.UnlockBits(data);

下記の SkiaSharp のソースと意味的に同等である。

1
2
using var bitmap = new SkiaSharp.SKBitmap(200, 200);
IntPtr poiner = bitmap.GetPixels();