文章目录
- SKCanvas方法
- DrawColor 填充颜色
- DrawDrawable 绘制封装对象
- DrawImage 高性能绘制图像
- SKBitmap与SKImage对比
- DrawPicture 绘制图像
- SKPicture
- DrawPoint / DrawPoints 绘制点
- DrawRoundRect/DrawRoundRectDifference绘制圆角矩形
- DrawSurface 绘制Surface
- DrawTextOnPath沿路径绘制文字
SKCanvas方法
DrawColor 填充颜色
public void DrawColor (SkiaSharp.SKColor color, SkiaSharp.SKBlendMode mode = SkiaSharp.SKBlendMode.Src);
public void DrawColor (SkiaSharp.SKColorF color, SkiaSharp.SKBlendMode mode = SkiaSharp.SKBlendMode.Src);
使用指定颜色和混合方式填充当前裁切区域。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
{canvas.DrawColor(SKColors.LightGreen, SKBlendMode.Src);canvas.ClipRect(new SKRect(100, 100, 300, 200));//将颜色填充当前裁切区域canvas.DrawColor(SKColors.Blue, SKBlendMode.SrcOver);paint.Color = SKColors.Red;paint.TextSize = 24;canvas.DrawText($"DrawColor", 95, 150, paint);
}
使用亮绿填充整个区域,修改裁切区域后,再次填充为蓝色。
DrawDrawable 绘制封装对象
public void DrawDrawable (SkiaSharp.SKDrawable drawable, float x, float y);
public void DrawDrawable (SkiaSharp.SKDrawable drawable, SkiaSharp.SKPoint p);
public void DrawDrawable (SkiaSharp.SKDrawable drawable, ref SkiaSharp.SKMatrix matrix);
绘制一个封装了绘制业务的对象。
- 封装一个绘制笑脸的业务逻辑。
/// <summary>
/// 封闭一个绘制笑脸对象
/// </summary>
public class FaceDrawable:SKDrawable
{protected override void OnDraw(SKCanvas canvas){using (var paint = new SKPaint()){paint.Color = SKColors.LightGreen;canvas.DrawCircle(100, 100, 100, paint);paint.Color = SKColors.Red;paint.IsStroke = true;canvas.DrawCircle(60,80,25, paint);canvas.DrawCircle(140, 80, 25, paint);canvas.DrawArc(new SKRect(75, 90, 125, 130), 45, 90, false, paint);} }
}
- 重复横、列多次绘制。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);var drawable = new FaceDrawable();using (var paint = new SKPaint())
{//多次绘制一组相同的对象var bounds=drawable.Bounds;for (float x = 0; x < this.Width - bounds.Width; x += bounds.Width){for(float y = 0; y < this.Height - bounds.Height; y += bounds.Height){canvas.DrawDrawable(drawable,x,y);}}
}
DrawImage 高性能绘制图像
public void DrawImage (SkiaSharp.SKImage image, SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint = default);
public void DrawImage (SkiaSharp.SKImage image, SkiaSharp.SKRect dest, SkiaSharp.SKPaint paint = default);
public void DrawImage (SkiaSharp.SKImage image, SkiaSharp.SKRect source, SkiaSharp.SKRect dest, SkiaSharp.SKPaint paint = default);
public void DrawImage (SkiaSharp.SKImage image, float x, float y, SkiaSharp.SKPaint paint = default);
相比SKBitmap,性能更优,但SKImage内容不可变。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);if (skBmp == null)
{skBmp = SKBitmap.Decode(@"Images\AIWoman.png");skBmp = skBmp.Resize(new SKSizeI(350, 350), SKFilterQuality.High);
}
if (skImg == null) skImg = SKImage.FromBitmap(skBmp);const int DrawCount = 1000;
using (var paint = new SKPaint())
{paint.IsAntialias = true;paint.FilterQuality = SKFilterQuality.High;paint.TextSize = 24;for (int i = 0; i < 2; i++){count += 1;var sw = Stopwatch.StartNew();for (int j = 0; j < DrawCount; j++){if (count % 2 == 0){canvas.DrawImage(skImg, 400, 20, paint);}else{canvas.DrawBitmap(skBmp, 0, 20, paint);}}sw.Stop();if (count % 2 == 0){canvas.DrawText($"DrawImage {DrawCount}times:{sw.ElapsedMilliseconds}ms", 400, 400, paint);}else{canvas.DrawText($"DrawBitmap {DrawCount}times:{sw.ElapsedMilliseconds}ms", 0, 400, paint);}}
}
对比多次使用SKBitmap与SKImage绘制同一幅图像。
SKBitmap与SKImage对比
SKBitmap
-
可变性:
SKBitmap
是可变的,允许对像素进行直接的读写操作。这使得它非常适合需要频繁修改图像内容的情况。 -
内存管理:
SKBitmap
的内存是可管理的,这意味着你可以控制它的分配和释放。开发者需要注意内存管理以防止内存泄漏。 -
使用场景:
适用于需要直接处理像素数据的场景,如图像编辑、动态生成图像等。
SKImage
-
不可变性:
SKImage
是不可变的,一旦创建后其内容无法更改。这使得它非常适合用于高效的图像显示和传递。 -
内存管理:
SKImage
通常是通过图形硬件加速的,因此在性能上优于SKBitmap
。内存管理更为自动化,不需要开发者显式地管理。 -
使用场景:
适用于图像渲染、显示和传输,如绘制在屏幕上、保存为文件等。
DrawPicture 绘制图像
public void DrawPicture (SkiaSharp.SKPicture picture, SkiaSharp.SKPaint paint = default);
public void DrawPicture (SkiaSharp.SKPicture picture, ref SkiaSharp.SKMatrix matrix, SkiaSharp.SKPaint paint = default);
public void DrawPicture (SkiaSharp.SKPicture picture, SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint = default);
public void DrawPicture (SkiaSharp.SKPicture picture, float x, float y, SkiaSharp.SKPaint paint = default);
SKPicture
主要用于记录绘图命令以便在以后重用。
-
高效的重绘:
SKPicture
可以记录一次绘图操作的所有命令,然后在需要的时候进行重放。这样可以避免每次重绘时重新执行复杂的绘图逻辑,提高绘图的效率。
-
减少CPU开销:
- 在一些复杂的绘图操作中,通过记录绘图命令并重放,可以减少CPU的计算开销,因为重放绘图命令比重新执行绘图逻辑所需的计算量更小。
-
方便的图形内容重用:
SKPicture
允许将绘图命令记录下来并在不同的地方重用。例如,可以在多个视图中重用相同的图形内容,而不需要每次都重新绘制。
-
支持多线程绘图:
SKPicture
的记录和重放机制使得绘图命令可以在后台线程中生成,然后在主线程中重放。这有助于实现更流畅的用户界面和更好的响应性。
-
简化复杂场景的处理:
- 对于一些复杂的场景绘制,可以先将场景绘制到
SKPicture
中,然后在需要的时候重放这个SKPicture
。这使得处理复杂场景变得更加简单和直观。
- 对于一些复杂的场景绘制,可以先将场景绘制到
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);if (skPic == null)
{using (var recorder = new SKPictureRecorder()){using (var picCanvas = recorder.BeginRecording(SKRect.Create(400, 400)))using (var paint = new SKPaint()){paint.Color = SKColors.Red;paint.IsStroke = true;picCanvas.DrawCircle(60, 60, 50, paint);paint.IsStroke = false;paint.Color = SKColors.LightGreen;picCanvas.DrawRoundRect(100, 100, 350, 350, 50, 50, paint);}skPic = recorder.EndRecording();}
}using(var paint=new SKPaint())
{canvas.DrawPicture(skPic, paint);canvas.Translate(350, 350);canvas.DrawPicture(skPic, paint);
}
使用SKPictureRecorder生成SKPicture。
DrawPoint / DrawPoints 绘制点
public void DrawPoint (SkiaSharp.SKPoint p, SkiaSharp.SKColor color);
public void DrawPoint (SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint);
public void DrawPoint (float x, float y, SkiaSharp.SKColor color);
public void DrawPoint (float x, float y, SkiaSharp.SKPaint paint);
public void DrawPoints (SkiaSharp.SKPointMode mode, SkiaSharp.SKPoint[] points, SkiaSharp.SKPaint paint);
绘制点和点集
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
{canvas.DrawPoint(50,50,SKColors.Red);canvas.DrawPoint(100, 50, SKColors.Blue);paint.StrokeWidth = 10;paint.Color = SKColors.Red;canvas.DrawPoint(50, 100, paint);paint.Color = SKColors.Blue;paint.StrokeCap = SKStrokeCap.Round;canvas.DrawPoint(100, 100, paint);var points = new SKPoint[] {new SKPoint(200,20),new SKPoint(400,20),new SKPoint(400,120),new SKPoint(200,120),new SKPoint(200,160),new SKPoint(300,160)};canvas.DrawPoints(SKPointMode.Points, points, paint);paint.Color = SKColors.Green;canvas.Translate(0, 200);canvas.DrawPoints(SKPointMode.Lines, points, paint);paint.Color = SKColors.Red;canvas.Translate(0, 200);canvas.DrawPoints(SKPointMode.Polygon, points, paint);
}
可以绘制点集、线段(两个点连一条线),多段线
DrawRoundRect/DrawRoundRectDifference绘制圆角矩形
public void DrawRoundRect (SkiaSharp.SKRoundRect rect, SkiaSharp.SKPaint paint);
public void DrawRoundRect (SkiaSharp.SKRect rect, SkiaSharp.SKSize r, SkiaSharp.SKPaint paint);
public void DrawRoundRect (SkiaSharp.SKRect rect, float rx, float ry, SkiaSharp.SKPaint paint);
public void DrawRoundRect (float x, float y, float w, float h, float rx, float ry, SkiaSharp.SKPaint paint);
public void DrawRoundRectDifference (SkiaSharp.SKRoundRect outer, SkiaSharp.SKRoundRect inner, SkiaSharp.SKPaint paint);
绘制圆角矩形及两个圆角矩形之间的区域。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
using (var txtPaint = new SKPaint())
{txtPaint.IsAntialias = true;txtPaint.Color = SKColors.Red;txtPaint.TextSize = 18;paint.IsAntialias = true;paint.IsStroke = true;paint.StrokeWidth = 2;var rect = new SKRect(50, 50, 250, 150);canvas.DrawRoundRect(rect, new SKSize(20, 20), paint);canvas.DrawText($"DrawRoundRect, rx=20,ry=20", 50, 180, txtPaint);paint.Color = SKColors.Red;canvas.Translate(250, 0);canvas.DrawRoundRect(rect, new SKSize(50, 20), paint);canvas.DrawText($"DrawRoundRect, rx=50,ry=20", 50, 180, txtPaint);paint.Style = SKPaintStyle.Fill;canvas.Translate(0, 100);// 定义外部圆角矩形var outerRect = new SKRoundRect(new SKRect(100, 100, 500, 400), 50, 50);// 定义内部圆角矩形var innerRect = new SKRoundRect(new SKRect(120, 120, 480, 380), 30, 50);canvas.DrawRoundRectDifference(outerRect, innerRect, paint);}
绘制不同圆角的圆角矩形,及两个圆角矩形之间区域。
DrawSurface 绘制Surface
public void DrawSurface (SkiaSharp.SKSurface surface, SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint = default);
public void DrawSurface (SkiaSharp.SKSurface surface, float x, float y, SkiaSharp.SKPaint paint = default);
将Surface绘制到当前画布上。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
{using (var skBmp = new SKBitmap(400, 400))using (var surfaceA = SKSurface.Create(skBmp.Info, skBmp.RowBytes))using (var canvasA = surfaceA.Canvas)using (var paintA = new SKPaint()){paintA.IsAntialias = true;paintA.Color = SKColors.Red;paintA.IsStroke = true;canvasA.Clear(SKColors.White);canvasA.DrawRect(20, 20, 300, 120, paintA);canvasA.DrawCircle(200, 200, 100, paintA);canvas.DrawSurface(surfaceA, 50, 50);canvas.DrawText($"DrawSurface", 50, 350, paint);canvas.DrawSurface(surfaceA, 350, 350);canvas.DrawText($"DrawSurface", 350,650, paint);}
}
DrawTextOnPath沿路径绘制文字
public void DrawTextOnPath (string text, SkiaSharp.SKPath path, SkiaSharp.SKPoint offset, bool warpGlyphs, SkiaSharp.SKPaint paint);
public void DrawTextOnPath (string text, SkiaSharp.SKPath path, SkiaSharp.SKPoint offset, SkiaSharp.SKPaint paint);
public void DrawTextOnPath (string text, SkiaSharp.SKPath path, float hOffset, float vOffset, SkiaSharp.SKPaint paint);
定义一个路径,可使文字基线沿着路径还不是普通的直线。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);string text = $"SkiaSharp可以直接绘制一段绕着路径(如曲线)行走的文字,是不是很Cool!";
var path = new SKPath();path.MoveTo(50, 50); // 起始点
path.CubicTo(250, 400, 550, 100, 750, 600); // 三次贝塞尔曲线
var pathMeasure = new SKPathMeasure(path, false);using (var paint = new SKPaint())
{paint.IsAntialias = true;paint.Color = SKColors.Red;paint.TextSize = 22;if (timer == null){var pathLength = pathMeasure.Length / 2;hOffset = pathLength;timer = new System.Windows.Forms.Timer();timer.Interval = 30;timer.Tick += (o, t) =>{hOffset -= 2;if (hOffset <= -pathLength){hOffset = pathLength;}this.TNTechImageBox.Invalidate();};timer.Start();}paint.Typeface = SKTypeface.FromFamilyName("宋体");var vOffset = -paint.TextSize / 2; // 垂直偏移量,使文本中心对齐路径 canvas.DrawTextOnPath(text, path, hOffset, vOffset, paint);paint.IsStroke = true;canvas.DrawPath(path, paint);}
- 定义一段贝赛尔曲线
- 定义一段文字
- 定义一个定时器
- 使文字沿着曲线动态绘制。