【SkiaSharp绘图11】SKCanvas属性详解

SKCanvas

用于在位图、表面或其他绘图设备上执行 2D 图形操作。

  1. 绘图操作

    • SKCanvas 提供了丰富的绘图方法,如绘制几何图形(圆形、矩形、路径等)、文本、位图等。
    • 可以设置画笔(SKPaint)的颜色、样式、线宽等属性,实现各种绘制效果。
  2. 图像合成和组合

    • 可以将多个绘图操作合成为单个图像,支持透明度和混合模式,实现复杂的图形效果。
    • 支持在不同图层上进行绘制,并可以进行图层的合并和组合。
  3. 处理和转换

    • 支持坐标变换(平移、旋转、缩放等),方便实现复杂的图形变换和动画效果。
    • 可以通过剪切区域(ClipRectClipPath)限制绘制区域,优化绘制性能。
  4. 跨平台支持

    • SkiaSharp 是跨平台的,可以在 Windows、macOS、Linux 和移动平台(Android、iOS)上使用,SKCanvas 提供了统一的绘图 API。
  5. 高性能渲染

    • SkiaSharp 使用 GPU 加速和多线程优化,能够高效地处理大规模的图形渲染和复杂的图形操作。

构造SKCanvas

构造光栅 Surface

光栅后端绘制到内存块。该内存可由SkiaSharp或客户端自行管理。
默认推荐使用管理绘制画布命令的内存的对象SKSurface。
OnPaintSurface(object sender, SkiaSharp.Views.Desktop.SKPaintGLSurfaceEventArgs e)事件中e参数的Surface就是SKSurface对象。
可通过SKSurface.Create方法的不同参数创建由SkiaSharp或自行管理内存的SKSurface对象。

  1. 由SkiaSharp管理
var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);

var info = new SKImageInfo(400, 300);
//通过SKSurface获取Canvas
using (var skSurface = SKSurface.Create(info))
using (var skCanvas = skSurface.Canvas)
using (var skPaint = new SKPaint())
{
    skPaint.TextSize = 18;
    skPaint.Color = SKColors.LightGreen;
    skPaint.IsStroke = true;
    skCanvas.DrawRect(100, 100, 250, 100, skPaint);
    skCanvas.DrawText($"SKSurface1", 0, 200, skPaint);
    canvas.DrawSurface(skSurface, 0, 0, skPaint);
}
  1. 自动分配内存
var info2 = new SKImageInfo(400, 400);
//自行分配内存
var memory = Marshal.AllocCoTaskMem(info2.BytesSize);

try
{
    using (var surface2 = SKSurface.Create(info2, memory, info2.RowBytes))
    using (var canvas2 = surface2.Canvas)
    using (var paint = new SKPaint())
    {
        paint.Color = SKColors.Blue;
        paint.TextSize = 18;
        canvas2.DrawCircle(200, 200, 100, paint);
        canvas2.DrawText($"SKSurface2", 0, 200, paint);
        canvas.DrawSurface(surface2, 0, 350, paint);
    }
}
finally
{
    Marshal.FreeCoTaskMem(memory);
}

SKSurface.Create
在测试的过程,一开始不知为什么会出现两个矩形,还以为是SkiaSharp的BUG,后不知怎么搞的,又没事了…

构造GPU Surface

GPU Surface必须有一个GRContext对象来管理GPU上下文以及纹理和字体的相关缓存。
GRContext对象与OpenGL上下文或Vulkan设备一一匹配。
如果使用SKGLControl控件,默认的的e.Surface.Context就是启用了GPU的OpenGL

构造PDF文档

使用SkiaSharp直接绘制并生成PDF文档(不支持显示PDF)
PDF后端使用SKDocument而不是SKSurface,因为文档必须包含多个页面。

var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);

using (FileStream stream = new FileStream(@"Images\test.pdf", FileMode.CreateNew, FileAccess.Write))
using (var doc = SKDocument.CreatePdf(stream, 72))
using (var pdfCanvas = doc.BeginPage(600, 800))
using (var paint = new SKPaint())
{
    paint.Color = SKColors.LightGreen;
    paint.IsAntialias = true;
    paint.TextSize = 24;
    pdfCanvas.DrawText("Create PDF Doc by SkiaSharp", 20, 30, paint);
    pdfCanvas.DrawCircle(300, 400, 150, paint);
    doc.EndPage();
    doc.Close();
}
  1. 创建一个写的文件流
  2. 根据文件流和DPI创建SKDocument对象
  3. 根据SKDocument对象创建SKCanvas
  4. 可以SKCanvas绘制内容,生成PDF。

SKDocument.CreatePdf

构造XPS文档

与构造Pdf类似,用SKDocument.CreateXps

var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);

using (FileStream stream = new FileStream(@"Images\test.xps", FileMode.Create, FileAccess.Write))
using (var doc = SKDocument.CreatePdf(stream, 72))
using (var pdfCanvas = doc.BeginPage(600, 800))
using (var paint = new SKPaint())
{
    paint.Color = SKColors.LightGreen;
    paint.IsAntialias = true;
    paint.TextSize = 24;
    pdfCanvas.DrawText("Create XPS doc by SkiaSharp", 20, 30, paint);
    pdfCanvas.DrawCircle(300, 400, 150, paint);
    doc.EndPage();
    doc.Close();
}

在这里插入图片描述

构造SVG文档

使用SKSvgCanvas构造SVG文档。

using (FileStream stream = new FileStream(@"Images\test.svg", FileMode.Create, FileAccess.Write))
using (var svgCanvas = SKSvgCanvas.Create(new SKRect(0, 0, 600, 800), stream))
using (var paint = new SKPaint())
{
    paint.Color = SKColors.LightGreen;
    paint.IsAntialias = true;
    paint.TextSize = 24;
    svgCanvas.DrawText("Create SVG doc by SkiaSharp", 20, 30, paint);
    svgCanvas.DrawCircle(300, 400, 150, paint);
}

SKSvgCanvas.Create

SKNoDrawCanvas

构造不绘制的画布,是提供一个“无操作”的画布,这意味着它不会进行任何实际的绘图操作。一般用于性能测试、绘图命令的记录与分析、避免不必要的绘图。

变换

SKCanvas提供Scale、Skew、Translate、RotateDegrees、RotateRadians等常用的二维变换。
还可以使用SetMatrix指定变换矩阵。
使用ResetMatrix可重置矩阵状态。

剪裁和状态

可使用变换矩阵的Save方法来保存当前变换状态,然后使用Restore或RestoreToCount方法恢复以前的状态。还有SaveLayer方法。

构造函数

public SKCanvas (SkiaSharp.SKBitmap bitmap);

创建一个画布,其中包含要绘制的指定位图。

相关属性

DeviceClipBounds获取裁切边界(设备坐标系)

public SkiaSharp.SKRectI DeviceClipBounds { get; }

获取当前裁切边界(在设备坐标中)。

ClipRect修改裁切区域

public void ClipRect (SkiaSharp.SKRect rect, SkiaSharp.SKClipOperation operation = SkiaSharp.SKClipOperation.Intersect, bool antialias = false);

修改当前裁切区域

IsClipEmpty当前裁切区域是否为空

public bool IsClipEmpty { get; }

判断当前裁切区域是否为空。

IsClipRect裁切区域是否为矩形

public bool IsClipRect { get; }

判断当前裁切区域是否为矩形。

LocalClipBounds获取裁切边界(本地坐标系)

public SkiaSharp.SKRect LocalClipBounds { get; }

获取当前的裁切边界(本地坐标系中,矩阵变换后的)

SaveCount 状态记数

public int SaveCount { get; }

获取画布私有堆栈上的矩阵/裁切状态的数量。
当调用SKCanvas对象的Save()方法时,加1。调用Restore()时,减1。
一个新的画布的SaveCount为1。

TotalMatrix 变换矩阵

public SkiaSharp.SKMatrix TotalMatrix { get; }

获取当前画布的变换矩阵。

示例

var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
using (var paint = new SKPaint())
{
    paint.Color = SKColors.Red;
    paint.IsAntialias = true;
    paint.TextSize = 24;
    var yOffset = 50F;
    if (canvas.GetDeviceClipBounds(out var rect))
    {
        canvas.DrawText($"DeviceClipBounds:{rect}", 20, yOffset, paint);
    }
    yOffset += paint.FontSpacing;
    rect = new SKRectI(25, 20, 800, 800);
    //设置裁切区域
    canvas.ClipRect(rect);

    canvas.DrawText($"ClipRect:{rect}", 20, yOffset, paint);
    yOffset += paint.FontSpacing;
    if (canvas.GetDeviceClipBounds(out rect))
    {
        canvas.DrawText($"DeviceClipBounds:{rect}", 20, yOffset, paint);
        yOffset += paint.FontSpacing;
    }

    canvas.DrawText($"IsClipEmpty:{canvas.IsClipEmpty}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;
    canvas.DrawText($"IsClipRect:{canvas.IsClipRect}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    rect = SKRectI.Create(100, 50);
    canvas.DrawText($"ClipRect:{rect} Difference", 50, yOffset, paint);
    yOffset += paint.FontSpacing;
    canvas.ClipRect(rect, SKClipOperation.Difference);

    canvas.DrawText($"IsClipRect:{canvas.IsClipRect}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    canvas.DrawText($"LocalClipBounds:{canvas.LocalClipBounds}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    // 设置画布变换(如平移)
    canvas.Translate(50, 50);
    canvas.DrawText($"Translate(50, 50)", 50, yOffset, paint);
    yOffset += paint.FontSpacing;
    canvas.DrawText($"LocalClipBounds:{canvas.LocalClipBounds}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;
    if (canvas.GetDeviceClipBounds(out rect))
    {
        canvas.DrawText($"DeviceClipBounds:{rect}", 50, yOffset, paint);
        yOffset += paint.FontSpacing;
    }

    canvas.DrawText($"SaveCount:{canvas.SaveCount}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;
    canvas.Save();

    canvas.DrawText($"Call Save()", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    canvas.DrawText($"SaveCount:{canvas.SaveCount}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    canvas.Restore();

    canvas.DrawText($"Call Restore()", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    canvas.DrawText($"SaveCount:{canvas.SaveCount}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;

    using (var newCanvas = new SKCanvas(new SKBitmap()))
    {
        canvas.DrawText($"new SKCanvas SaveCount:{newCanvas.SaveCount}", 50, yOffset, paint);
        yOffset += paint.FontSpacing;
    }

    var matrix = canvas.TotalMatrix;
    canvas.DrawText($"TotalMatrix:{string.Join(",",matrix.Values)}", 50, yOffset, paint);
    yOffset += paint.FontSpacing;
}

SKCanvas属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图南科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值