skiasharp绘图必须绑定sksurface,不能直接new skcanvas;需复用资源、显式dispose非托管对象;跨平台字体须嵌入.ttf并fromstream加载;抗锯齿和滤镜质量需手动开启以提升清晰度。

SkiaSharp 初始化必须调用 SKImageInfo 或 SKSurface.Create 才能绘图
直接 new SKCanvas 会抛出 System.NotSupportedException —— 它没有无参构造函数,也不能独立存在。所有绘图操作必须绑定到一个有效的绘图表面(SKSurface)上。
常见做法是:在 Windows Forms 中用 SKBitmap + SKSurface.Create;在 WPF 中用 WriteableBitmap 配合 SKSurface.Create;在 .NET MAUI 中直接用 SKCanvasView 的 Canvas 参数。
- Windows Forms 示例:
var bitmap = new SKBitmap(width, height); var surface = SKSurface.Create(new SKImageInfo(width, height), bitmap); var canvas = surface.Canvas; - 避免在 UI 线程外反复创建
SKSurface,尤其在动画循环中——应复用SKSurface或至少复用SKBitmap - MAUI 中不要手动 new
SKCanvas,而是通过SKCanvasView.PaintSurface事件的e.Surface.Canvas获取
SKPaint 的 IsAntialias 和 FilterQuality 决定线条/文字清晰度
默认情况下 SKPaint 抗锯齿关闭、滤镜质量低,绘出的圆弧、斜线、小字号文字容易发虚或出现像素断裂。这不是 bug,是 Skia 的默认性能权衡。
- 开启抗锯齿:
paint.IsAntialias = true;(对路径、文字、图像缩放都生效) - 提升缩放质量:
paint.FilterQuality = SKFilterQuality.High;(尤其在canvas.DrawBitmap缩放时明显) - 文字渲染建议额外设置:
paint.TextEncoding = SKTextEncoding.Utf8;和paint.Typeface = SKTypeface.FromFamilyName("Segoe UI", SKFontStyle.Bold); - 注意:高频开关
IsAntialias本身不耗资源,但开启后绘制路径的 CPU 开销会上升约 15–20%
跨平台字体加载必须用 SKTypeface.FromStream 或嵌入资源
直接传入系统字体名(如 "Arial")在 macOS 或 Linux 上大概率失败,.NET MAUI Android/iOS 也受限于沙盒和字体注册机制。SkiaSharp 不走系统字体管理器,它需要字节流或已注册的 typeface。
- 推荐方式:把 .ttf 文件作为
EmbeddedResource,运行时用Assembly.GetExecutingAssembly().GetManifestResourceStream(...)加载,再传给SKTypeface.FromStream(stream) - Android 上可访问
/system/fonts/下字体,但需 root;iOS 不允许读取系统字体路径 - MAUI 中不要依赖
SKTypeface.Default渲染中文——它在非 Windows 平台常 fallback 到无汉字的字体,导致方块 - 调试技巧:用
typeface.FamilyName打印确认加载成功,空字符串表示加载失败
释放 SKBitmap、SKSurface、SKTypeface 必须显式调用 Dispose()
这些类型包装了非托管内存(Skia 的 native sk_bitmap_t / sk_surface_t),GC 不会自动回收。漏掉 Dispose() 会导致内存缓慢增长,Windows 上可能几 MB/秒,Android 上更容易触发 OOM。
- 务必用
using块包裹短期对象:using var bitmap = new SKBitmap(...); using var surface = SKSurface.Create(...); -
SKTypeface是线程安全且可共享的,建议全局缓存(如static readonly SKTypeface ChineseFont = LoadMyFont();),避免重复加载 - MAUI 中
SKCanvasView的PaintSurface事件里拿到的e.Surface由框架管理,**不要调用Dispose()**;仅自己 new 出来的才需释放 - 检查泄漏:在 Visual Studio 的“诊断工具”中观察“Native Heap”趋势,或用
dotnet-counters --process-id [pid] Microsoft.Extensions.DependencyInjection:DiagnosticSource辅助定位
跨平台绘图真正难的不是 API 调用,而是每个平台对资源生命周期、字体路径、DPI 感知的隐式差异。哪怕一行 canvas.DrawRect,背后涉及 surface 格式兼容性、GPU 后端切换、字体回退链——这些细节不踩一遍坑很难凭文档猜全。










