文章目錄
- 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);}
- 定義一段貝賽爾曲線
- 定義一段文字
- 定義一個定時器
- 使文字沿著曲線動態繪制。