一、SkiaSharp 简介

SkiaSharp 是一个强大的跨平台 2D 图形库,它基于 Google 的 Skia 图形引擎,为 .NET 开发者提供了丰富的图形处理和绘制功能。借助 SkiaSharp,开发者可以在 Windows、macOS、Linux 等多种操作系统以及桌面、移动设备上创建精美的图形应用。

二、SkiaSharp 主要功能及示例代码

(一)基本图形绘制

1. 点和线

SkiaSharp 允许我们绘制单个点或一系列连续的点,同时还能绘制直线、折线等。我们可以设置线的宽度、颜色、样式(如实线、虚线)等属性。

using SkiaSharp;
// 创建一个新的 SKSurface 对象
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    // 清除画布
    canvas.Clear(SKColors.White);
    // 创建画笔
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Black,
        StrokeWidth = 5,
        Style = SKPaintStyle.Stroke
    };
    // 绘制点
    canvas.DrawPoint(100, 100, paint);
    // 绘制直线
    canvas.DrawLine(200, 100, 300, 200, paint);
    // 设置线样式为虚线
    paint.PathEffect = SKPathEffect.CreateDash(new float[] { 10, 5 }, 0);
    canvas.DrawLine(400, 100, 500, 200, paint);
    // 保存图像
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("points_and_lines.png"))
    {
        data.SaveTo(stream);
    }
}

2. 矩形

可以绘制普通矩形、圆角矩形,并且能对矩形进行填充或仅绘制边框。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Red,
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 5
    };
    // 绘制普通矩形
    SKRect rect = new SKRect(100, 100, 300, 300);
    canvas.DrawRect(rect, paint);
    // 绘制圆角矩形
    paint.Style = SKPaintStyle.Fill;
    paint.Color = SKColors.Blue;
    canvas.DrawRoundRect(rect, 20, 20, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("rectangles.png"))
    {
        data.SaveTo(stream);
    }
}

3. 圆形和椭圆

可绘制标准圆形以及不同长短轴比例的椭圆,同样支持填充和描边操作。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Green,
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 5
    };
    // 绘制圆形
    canvas.DrawCircle(200, 200, 100, paint);
    // 绘制椭圆
    paint.Style = SKPaintStyle.Fill;
    paint.Color = SKColors.Yellow;
    SKRect ovalRect = new SKRect(400, 100, 600, 300);
    canvas.DrawOval(ovalRect, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("circles_and_ovals.png"))
    {
        data.SaveTo(stream);
    }
}

4. 弧形和扇形

可以根据指定的起始角度和扫过角度绘制弧形和扇形,常用于绘制饼图、进度条等场景。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Purple,
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 5
    };
    SKRect arcRect = new SKRect(200, 200, 400, 400);
    // 绘制弧形
    canvas.DrawArc(arcRect, 0, 90, false, paint);
    // 绘制扇形
    paint.Style = SKPaintStyle.Fill;
    canvas.DrawArc(arcRect, 180, 90, true, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("arcs_and_sectors.png"))
    {
        data.SaveTo(stream);
    }
}

(二)路径绘制

1. 自定义形状

通过创建 SKPath 对象,我们可以定义复杂的自定义形状,例如多边形、不规则曲线等。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Orange,
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 5
    };
    SKPath path = new SKPath();
    path.MoveTo(100, 100);
    path.LineTo(200, 200);
    path.LineTo(300, 100);
    path.Close();
    canvas.DrawPath(path, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("custom_path.png"))
    {
        data.SaveTo(stream);
    }
}

2. 路径操作

支持对路径进行合并、相交、相减等布尔操作,从而创建更复杂的图形组合。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Brown,
        Style = SKPaintStyle.Fill
    };
    SKPath path1 = new SKPath();
    path1.AddCircle(200, 200, 100);
    SKPath path2 = new SKPath();
    path2.AddRect(150, 150, 250, 250);
    SKPath combinedPath = new SKPath();
    combinedPath.Op(path1, path2, SKPathOp.Intersect);
    canvas.DrawPath(combinedPath, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("path_operation.png"))
    {
        data.SaveTo(stream);
    }
}

(三)文本绘制

1. 基本文本渲染

能够在画布上指定位置绘制文本,并设置字体、字号、颜色、对齐方式等属性。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 30,
        Typeface = SKTypeface.FromFamilyName("Arial")
    };
    canvas.DrawText("Hello, SkiaSharp!", 100, 100, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("text_rendering.png"))
    {
        data.SaveTo(stream);
    }
}

2. 文本布局

支持多行文本的布局,自动处理换行、缩进等。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 20,
        Typeface = SKTypeface.FromFamilyName("Arial")
    };
    string multiLineText = "This is a multi-line text example.\nIt will be automatically wrapped.";
    SKRect bounds = new SKRect(100, 100, 400, 400);
    canvas.DrawText(multiLineText, bounds, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("text_layout.png"))
    {
        data.SaveTo(stream);
    }
}

(四)图像和位图处理

1. 图像加载和保存

可以从文件、流或内存中加载常见格式(如 PNG、JPEG)的图像,也能将绘制结果保存为图像文件。

using SkiaSharp;
// 加载图像
using (SKBitmap loadedBitmap = SKBitmap.Decode("input.png"))
using (SKCanvas canvas = new SKCanvas(loadedBitmap))
{
    // 在图像上绘制一些内容
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Red,
        TextSize = 50
    };
    canvas.DrawText("Watermark", 100, 100, paint);
    // 保存修改后的图像
    using (SKData data = loadedBitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("output.png"))
    {
        data.SaveTo(stream);
    }
}

2. 位图操作

对位图进行像素级别的操作,如获取和设置像素颜色、调整亮度、对比度、灰度化、色彩转换等,还可以进行图像的缩放、旋转、裁剪等变换操作。

using SkiaSharp;
using (SKBitmap bitmap = SKBitmap.Decode("input.png"))
{
    // 灰度化
    for (int y = 0; y < bitmap.Height; y++)
    {
        for (int x = 0; x < bitmap.Width; x++)
        {
            SKColor color = bitmap.GetPixel(x, y);
            byte gray = (byte)((color.Red + color.Green + color.Blue) / 3);
            SKColor grayColor = new SKColor(gray, gray, gray, color.Alpha);
            bitmap.SetPixel(x, y, grayColor);
        }
    }
    // 保存灰度化后的图像
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("grayscale.png"))
    {
        data.SaveTo(stream);
    }
}

(五)颜色和渐变

1. 颜色处理

支持各种颜色模式,如 RGB、RGBA、HSV 等,可以方便地创建和操作颜色对象。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    // 创建 RGB 颜色
    SKColor rgbColor = new SKColor(255, 0, 0);
    SKPaint paint = new SKPaint
    {
        Color = rgbColor,
        Style = SKPaintStyle.Fill
    };
    canvas.DrawRect(new SKRect(100, 100, 300, 300), paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("color_handling.png"))
    {
        data.SaveTo(stream);
    }
}

2. 渐变填充

可以创建线性渐变、径向渐变和锥形渐变,并将其应用到图形的填充中。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPoint startPoint = new SKPoint(100, 100);
    SKPoint endPoint = new SKPoint(300, 300);
    SKColor[] colors = { SKColors.Red, SKColors.Yellow };
    SKShader shader = SKShader.CreateLinearGradient(startPoint, endPoint, colors, null, SKShaderTileMode.Clamp);
    SKPaint paint = new SKPaint
    {
        Shader = shader,
        Style = SKPaintStyle.Fill
    };
    canvas.DrawRect(new SKRect(100, 100, 300, 300), paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("gradient_fill.png"))
    {
        data.SaveTo(stream);
    }
}

(六)变换和矩阵操作

1. 平移、旋转和缩放

通过矩阵变换可以对绘制的图形进行平移、旋转和缩放操作。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Blue,
        Style = SKPaintStyle.Fill
    };
    SKMatrix matrix = SKMatrix.MakeTranslation(200, 200);
    matrix = matrix.PostConcat(SKMatrix.MakeRotationDegrees(45));
    matrix = matrix.PostConcat(SKMatrix.MakeScale(2, 2));
    canvas.SetMatrix(matrix);
    canvas.DrawRect(new SKRect(-50, -50, 50, 50), paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("transformations.png"))
    {
        data.SaveTo(stream);
    }
}

2. 自定义变换

可以创建自定义的变换矩阵,实现更复杂的变形效果。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Green,
        Style = SKPaintStyle.Fill
    };
    SKMatrix customMatrix = new SKMatrix
    {
        ScaleX = 1.5f,
        SkewY = 0.5f,
        TransX = 100,
        TransY = 200
    };
    canvas.SetMatrix(customMatrix);
    canvas.DrawRect(new SKRect(-50, -50, 50, 50), paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("custom_transformation.png"))
    {
        data.SaveTo(stream);
    }
}

(七)阴影和特效

1. 阴影绘制

为图形添加阴影效果,增强图形的立体感和层次感。可以使用 SKPaintImageFilter 属性结合 SKImageFilter.CreateDropShadow 方法来实现。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    SKPaint paint = new SKPaint
    {
        Color = SKColors.Black,
        Style = SKPaintStyle.Fill
    };
    // 创建阴影滤镜
    paint.ImageFilter = SKImageFilter.CreateDropShadow(
        dx: 10,
        dy: 10,
        sigmaX: 5,
        sigmaY: 5,
        color: SKColors.Gray,
        mode: SKDropShadowImageFilterShadowMode.DrawShadowAndForeground
    );
    // 绘制圆形,此时圆形会带有阴影
    canvas.DrawCircle(400, 300, 100, paint);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("shadow_example.png"))
    {
        data.SaveTo(stream);
    }
}

在上述代码中,SKImageFilter.CreateDropShadow 方法的参数含义如下:

  • dxdy:分别表示阴影在 X 轴和 Y 轴方向上的偏移量。
  • sigmaXsigmaY:控制阴影的模糊程度,值越大,阴影越模糊。
  • color:阴影的颜色。
  • mode:指定是只绘制阴影、只绘制前景图形还是两者都绘制。

2. 模糊和滤镜

应用模糊、锐化、色彩调整等滤镜效果,提升图像的视觉质量。下面以高斯模糊为例进行说明。

using SkiaSharp;
// 加载原始图像
using (SKBitmap sourceBitmap = SKBitmap.Decode("input.png"))
{
    using (SKSurface surface = SKSurface.Create(new SKImageInfo(sourceBitmap.Width, sourceBitmap.Height)))
    {
        SKCanvas canvas = surface.Canvas;
        // 创建模糊滤镜
        SKImageFilter blurFilter = SKImageFilter.CreateBlur(
            sigmaX: 5,
            sigmaY: 5,
            quality: SKFilterQuality.High
        );
        SKPaint paint = new SKPaint
        {
            ImageFilter = blurFilter
        };
        // 在画布上绘制应用滤镜后的图像
        canvas.DrawBitmap(sourceBitmap, 0, 0, paint);
        // 获取处理后的图像
        using (SKImage outputImage = surface.Snapshot())
        using (SKData data = outputImage.Encode(SKEncodedImageFormat.Png, 100))
        using (System.IO.FileStream stream = System.IO.File.OpenWrite("blurred_output.png"))
        {
            data.SaveTo(stream);
        }
    }
}

在这个示例中,SKImageFilter.CreateBlur 方法用于创建高斯模糊滤镜,sigmaXsigmaY 控制模糊的强度,quality 指定模糊的质量。

(八)图形混合模式

支持多种图形混合模式,如正常、叠加、柔光等,通过不同的混合模式可以将多个图形或图像进行组合,创造出独特的视觉效果。

using SkiaSharp;
using (SKBitmap bitmap = new SKBitmap(800, 600))
using (SKCanvas canvas = new SKCanvas(bitmap))
{
    canvas.Clear(SKColors.White);
    // 绘制第一个圆形
    SKPaint paint1 = new SKPaint
    {
        Color = SKColors.Red,
        Style = SKPaintStyle.Fill
    };
    canvas.DrawCircle(200, 300, 100, paint1);
    // 设置混合模式为叠加
    SKPaint paint2 = new SKPaint
    {
        Color = SKColors.Blue,
        Style = SKPaintStyle.Fill,
        BlendMode = SKBlendMode.Overlay
    };
    // 绘制第二个圆形,与第一个圆形重叠部分会应用混合模式
    canvas.DrawCircle(300, 300, 100, paint2);
    using (SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100))
    using (System.IO.FileStream stream = System.IO.File.OpenWrite("blend_mode_example.png"))
    {
        data.SaveTo(stream);
    }
}

在上述代码中,SKBlendMode.Overlay 是一种混合模式,它会将两个图形的颜色进行叠加处理,产生独特的视觉效果。SkiaSharp 还支持许多其他的混合模式,如 SKBlendMode.Normal(正常模式)、SKBlendMode.SoftLight(柔光模式)等。

(九)硬件加速和性能优化

SkiaSharp 支持利用 GPU 进行硬件加速,提高图形绘制的性能,尤其是在处理复杂图形和高分辨率图像时表现出色。同时,它还提供了一些性能优化的策略和方法,如使用缓存、批量绘制等。

1. 使用硬件加速

在 Xamarin.Android 项目中,可以通过创建 SKGLSurfaceView 来启用 OpenGL 硬件加速。以下是一个简单的示例:

using Android.App;
using Android.OS;
using Android.Views;
using SkiaSharp;
using SkiaSharp.Views.Android;
namespace SkiaSharpHardwareAcceleration
{
    [Activity(Label = "SkiaSharpHardwareAcceleration", MainLauncher = true)]
    public class MainActivity : Activity
    {
        private SKGLSurfaceView skiaView;
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            skiaView = new SKGLSurfaceView(this);
            skiaView.PaintSurface += OnPaintSurface;

            SetContentView(skiaView);
        }
        private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
        {
            SKCanvas canvas = e.Surface.Canvas;
            canvas.Clear(SKColors.White);
            SKPaint paint = new SKPaint
            {
                Color = SKColors.Black,
                StrokeWidth = 5
            };
            canvas.DrawLine(100, 100, 300, 300, paint);
        }
    }
}

在这个示例中,SKGLSurfaceView 利用 OpenGL 进行硬件加速,提升了图形绘制的性能。

2. 使用缓存

对于一些经常使用的图形元素,如字体、画笔等,可以进行缓存,避免重复创建。

private static SKPaint cachedPaint;
public void DrawSomething(SKCanvas canvas)
{
    if (cachedPaint == null)
    {
        cachedPaint = new SKPaint
        {
            Color = SKColors.Red,
            TextSize = 30
        };
    }
    canvas.DrawText("Cached Text", 100, 100, cachedPaint);
}

通过缓存 SKPaint 对象,减少了每次绘制时创建新对象的开销,提高了性能。

(十)跨平台支持

SkiaSharp 可以在多种操作系统(如 Windows、macOS、Linux)和设备(如桌面、移动设备)上运行,并且可以与不同的 .NET 应用程序框架(如 .NET Core、Xamarin)集成,方便开发者创建跨平台的图形应用。以下是一个在 Xamarin.Forms 中使用 SkiaSharp 的简单示例:

1. 创建 Xamarin.Forms 项目

首先,创建一个新的 Xamarin.Forms 项目。

2. 安装 SkiaSharp 相关 NuGet 包

在项目中安装 SkiaSharpSkiaSharp.Views.Forms 等相关 NuGet 包。

3. 创建自定义 SkiaSharp 视图

using SkiaSharp;
using SkiaSharp.Views.Forms;
using Xamarin.Forms;
namespace SkiaSharpXamarinFormsExample
{
    public class CustomSkiaView : SKCanvasView
    {
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
        {
            base.OnPaintSurface(e);
            SKCanvas canvas = e.Surface.Canvas;
            canvas.Clear(SKColors.White);
            SKPaint paint = new SKPaint
            {
                Color = SKColors.Blue,
                Style = SKPaintStyle.Fill
            };
            canvas.DrawCircle(100, 100, 50, paint);
        }
    }
}

4. 在 XAML 中使用自定义视图

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SkiaSharpXamarinFormsExample"
             x:Class="SkiaSharpXamarinFormsExample.MainPage">
    <local:CustomSkiaView />
</ContentPage>

通过以上步骤,我们可以在 Xamarin.Forms 应用中使用 SkiaSharp 进行图形绘制,并且这个应用可以在 Android、iOS 等多个平台上运行。

SkiaSharp 提供了丰富的功能和强大的性能,无论是简单的图形绘制还是复杂的图像处理,都能轻松应对。通过合理运用这些功能,开发者可以创建出高质量的跨平台图形应用。