1. 为什么选择SkiaSharp做跨平台图形开发第一次接触SkiaSharp是在开发一个需要跨平台验证码生成组件的项目中。当时尝试了好几种图形库要么性能跟不上要么跨平台兼容性有问题。直到发现了SkiaSharp这个由Google自家产品都在用的Skia引擎支持的.NET封装库问题才迎刃而解。SkiaSharp最大的优势在于它真正实现了一次编写到处运行。我曾在Windows、macOS、Linux甚至树莓派上测试过同一段绘图代码输出效果完全一致。底层基于C的Skia引擎保证了性能而.NET封装层则让C#开发者能够用熟悉的语法调用所有功能。相比System.Drawing这类传统图形库SkiaSharp支持更现代的图形特性硬件加速的2D渲染高质量的文本抗锯齿完善的图像滤镜系统矢量图形路径操作在移动端的表现尤其突出。记得有个客户需要在低配Android平板上实时绘制心电图波形用SkiaSharp即使每秒刷新60帧也毫无压力。这要归功于它自动适配不同平台的GPU加速特性。2. 快速搭建开发环境2.1 基础环境配置在Visual Studio中新建一个.NET控制台项目通过NuGet添加SkiaSharp核心库只需要一行命令dotnet add package SkiaSharp如果要开发桌面应用还需要额外安装平台特定的视图包。比如在Windows上开发WinForms应用时dotnet add package SkiaSharp.Views.WindowsForms我建议同时安装SkiaSharp.Extended这个扩展包它提供了很多实用工具dotnet add package SkiaSharp.Extended2.2 跨平台注意事项在不同平台上运行时有几个常见坑点需要注意Linux系统可能需要安装额外的字体库WebAssembly版本需要处理异步加载iOS上要注意内存管理规则这里分享一个字体处理的技巧。跨平台时最稳妥的方式是打包字体文件到程序集中var typeface SKTypeface.FromStream(Assembly.GetExecutingAssembly() .GetManifestResourceStream(YourApp.Resources.Fonts.Roboto.ttf));3. 核心图形操作实战3.1 绘制基础图形创建画布是第一步我习惯用这种方式初始化using (var surface SKSurface.Create(new SKImageInfo(800, 600))) { var canvas surface.Canvas; canvas.Clear(SKColors.White); // 绘制矩形 var rectPaint new SKPaint { Color SKColors.Blue, IsStroke true, StrokeWidth 5 }; canvas.DrawRect(new SKRect(100, 100, 300, 300), rectPaint); // 绘制圆形 var circlePaint new SKPaint { Color SKColors.Red, IsAntialias true }; canvas.DrawCircle(400, 400, 50, circlePaint); }实际项目中我发现SKPaint对象的复用能显著提升性能。如果频繁创建销毁Paint对象在移动设备上可能导致卡顿。3.2 高级图像处理SkiaSharp的图像滤镜系统非常强大。这里演示如何给图片添加模糊效果using (var original SKBitmap.Decode(input.jpg)) using (var surface SKSurface.Create(new SKImageInfo(original.Width, original.Height))) { var canvas surface.Canvas; var paint new SKPaint { ImageFilter SKImageFilter.CreateBlur(10, 10) }; canvas.DrawBitmap(original, 0, 0, paint); using (var image surface.Snapshot()) using (var data image.Encode(SKEncodedImageFormat.Jpeg, 90)) using (var stream File.OpenWrite(output.jpg)) { data.SaveTo(stream); } }最近一个电商项目就用这个特性实现了商品图片的毛玻璃效果背景客户反馈视觉效果很专业。4. 性能优化技巧4.1 对象复用策略经过多次性能测试我发现这些对象应该尽量复用SKPaintSKTypefaceSKPathSKShader典型的优化案例是绘制大量相似图形时// 错误做法 - 每次循环都新建Paint for (int i 0; i 1000; i) { var paint new SKPaint(); // 这会导致严重性能问题 canvas.DrawRect(..., paint); } // 正确做法 - 复用Paint对象 using (var paint new SKPaint()) { for (int i 0; i 1000; i) { canvas.DrawRect(..., paint); } }4.2 离屏渲染技巧对于复杂图形预渲染到离屏表面能显著提升性能// 创建离屏表面 using (var offscreen SKSurface.Create(new SKImageInfo(200, 200))) { // 在离屏表面绘制复杂图形 var offCanvas offscreen.Canvas; DrawComplexGraphics(offCanvas); // 在主表面绘制离屏内容 using (var image offscreen.Snapshot()) { mainCanvas.DrawImage(image, 0, 0); } }在开发图表控件时这个技巧让渲染性能提升了3倍以上。特别是在需要频繁重绘的场景下优势更加明显。5. 实战案例验证码生成器结合前面所学我们来实现一个完整的验证码生成器。这个版本增加了扭曲变形和颜色渐变等高级特性public SKBitmap GenerateCaptcha(int width, int height, string code) { var imageInfo new SKImageInfo(width, height); using (var surface SKSurface.Create(imageInfo)) { var canvas surface.Canvas; canvas.Clear(SKColors.WhiteSmoke); // 创建渐变背景 using (var shader SKShader.CreateLinearGradient( new SKPoint(0, 0), new SKPoint(width, height), new[] { SKColors.LightBlue, SKColors.LightGreen }, null, SKShaderTileMode.Clamp)) using (var bgPaint new SKPaint { Shader shader }) { canvas.DrawRect(new SKRect(0, 0, width, height), bgPaint); } // 绘制干扰线 using (var linePaint new SKPaint { Color SKColors.Gray.WithAlpha(128), StrokeWidth 1, IsAntialias true }) { var random new Random(); for (int i 0; i 15; i) { canvas.DrawLine( random.Next(width), random.Next(height), random.Next(width), random.Next(height), linePaint); } } // 绘制验证码文本 using (var textPaint new SKPaint { IsAntialias true, TextSize height * 0.6f, FakeBoldText true }) { // 为每个字符设置不同颜色和位置偏移 var charWidth width / code.Length; for (int i 0; i code.Length; i) { textPaint.Color new SKColor( (byte)Random.Shared.Next(256), (byte)Random.Shared.Next(256), (byte)Random.Shared.Next(256)); // 计算字符位置 var x i * charWidth Random.Shared.Next(-5, 5); var y height * 0.7f Random.Shared.Next(-10, 10); // 保存当前画布状态 canvas.Save(); // 应用随机旋转 canvas.RotateDegrees(Random.Shared.Next(-15, 15), x, y); // 绘制字符 canvas.DrawText(code[i].ToString(), x, y, textPaint); // 恢复画布状态 canvas.Restore(); } } // 添加波纹扭曲效果 using (var effect SKImageFilter.CreateDisplacementMapEffect( SKDisplacementMapEffectChannelSelector.R, SKDisplacementMapEffectChannelSelector.G, 5f, SKImageFilter.CreatePerlinNoiseTurbulence(0.05f, 0.05f, 2, 0.5f))) using (var paint new SKPaint { ImageFilter effect }) { canvas.DrawRect(new SKRect(0, 0, width, height), paint); } return SKBitmap.FromImage(surface.Snapshot()); } }这个实现用到了SkiaSharp的多个高级特性线性渐变填充背景随机干扰线字符级的位置和颜色随机化基于Perlin噪声的扭曲效果在实际部署中这个验证码生成器每天要处理超过50万次请求运行在各种不同的设备上表现非常稳定。