【SkiaSharp绘图11】SKCanvas属性详解

文章目录

  • SKCanvas
  • 构造SKCanvas
    • 构造光栅 Surface
    • 构造GPU Surface
    • 构造PDF文档
    • 构造XPS文档
    • 构造SVG文档
    • SKNoDrawCanvas
  • 变换
  • 剪裁和状态
  • 构造函数
  • 相关属性
    • DeviceClipBounds获取裁切边界(设备坐标系)
    • ClipRect修改裁切区域
    • IsClipEmpty当前裁切区域是否为空
    • IsClipRect裁切区域是否为矩形
    • LocalClipBounds获取裁切边界(本地坐标系)
    • SaveCount 状态记数
    • TotalMatrix 变换矩阵
    • 示例

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属性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/747616.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C3P0数据库连接池

目录 一:连接池介绍 1.1连接池解决的问题 2.常用的数据库连接池 二:c3p0介绍 2.1C3P0介绍: 2.2C3P0快速入门 1.常用参数说明 2.API介绍 3.使用步骤 1.导入jar包c3p0-0.9.1.2.jar 2.编写c3p0-config.xml配置文件,配置对…

深入探索:大型语言模型消除幻觉的解决之道

随着人工智能技术的飞速发展,大型语言模型(LLMs)已经成为自然语言处理领域的明星。它们以其庞大的知识库和生成连贯、上下文相关文本的能力,极大地推动了研究、工业和社会的进步。然而,这些模型在生成文本时可能会产生…

27. 高级特性(下)

目录 一、为了类型安全和抽象而使用 newtype 模式二、使用类型别名创建类型同义词2.1 使用type关键赋予现有类型一个别名2.2 减少重复2.3 与Result<T, E>结合使用2.4 从不返回的 never type 三、高级函数和闭包3.1 函数指针3.2 返回闭包 四、宏4.1 宏和函数的区别4.2 mac…

2024 最新推广服务 API 推荐,助力业务腾飞

在数字化营销的浪潮中&#xff0c;API 服务正以其强大的功能和高效的特性&#xff0c;成为企业和开发者们实现精准推广、优化营销效果的得力助手。2024 年的今天&#xff0c;各种创新的 API 服务层出不穷&#xff0c;为广告投放、数据洞察等领域带来了前所未有的机遇。在接下来…

echarts隔行背景色

看了下使用说明&#xff0c;试了半天终于搞对了 参考文档&#xff1a;Documentation - Apache ECharts option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [120, 200, 150, 80, 70, 110, 130],type: bar,mar…

视频共享融合赋能平台LntonCVS视频监控业务平台建设安全煤矿矿井应用方案

随着我国经济的飞速增长&#xff0c;煤炭作为主要的能源之一&#xff0c;在我国的能源结构中扮演着至关重要的角色。然而&#xff0c;煤矿事故的频繁发生&#xff0c;不仅造成了巨大的人员伤亡和财产损失&#xff0c;也对社会产生了深远的负面影响。因此&#xff0c;实现煤矿的…

多家国产大模型提供OpenAI API服务替代方案,谷歌将推出明星网红AI聊天机器人

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 1、OpenAI终止对中国提供服务 6月25日凌晨&#xff0c;多个用户收到OpenAI的推送邮件&#xff0c;信中称&#xff0c;自今年7月9日起&#xff0c;将开始阻止来自非支持国家和地区的API&#xff08;应…

华为od-C卷200分题目3 - 两个字符串间的最短路径问题

华为od-C卷200分题目3 - 两个字符串间的最短路径问题 题目描述 给定两个字符串&#xff0c;分别为字符串A与字符串B。 例如A字符串为ABCABBA&#xff0c;B字符串为CBABAC可以得到下图m*n的二维数组&#xff0c;定义原点为(0, 0)&#xff0c;终点为(m, n)&#xff0c;水平与垂…

python自动化系列:自动将工作簿下的所有工作表合并到新工作表

作品介绍 作品名称&#xff1a;自动将工作簿下的所有工作表合并到新工作表 开发环境&#xff1a;PyCharm 2023.3.4 python3.7 用到的库&#xff1a;os、xlwings 作品简介&#xff1a;该实例使用xlwings库来操作Excel文件&#xff0c;其主要功能是将一个工作簿中所有工作表…

玩机进阶教程----MTK芯片使用Maui META修复基带 改写参数详细教程步骤解析

目前mtk芯片与高通芯片在主流机型 上使用比较普遍。但有时候版本更新或者误檫除分区等等原因会导致手机基带和串码丢失的故障。mtk芯片区别与高通。在早期mtk芯片中可以使用工具SN_Writer_Tool读写参数。但一些新版本机型兼容性不太好。今天使用另外一款工具来演示mtk芯片改写参…

打破数据分析壁垒:SPSS复习必备(十)

Means过程 统计学上的定义和计算公式 定义&#xff1a;Means过程是SPSS计算各种基本描述统计量的过程&#xff0c;其实就是按照用户指定条件&#xff0c;对样本进行分组计算均数和标准差&#xff0c;如按性别计算各组的均数和标准差。 用户可以指定一个或多个变量作为分组变…

上古世纪台服注册账号+下载客户端全方位图文教程

又一款新的MMRPG游戏即将上线啦&#xff0c;游戏名称叫做《上古世纪》游戏采用传统MMO类型游戏的玩法&#xff0c;但是开发商采用了先进的游戏引擎&#xff0c;让玩家们可以享受到极致的视觉体验。同时游戏的背景是建立在大陆分崩离析的基础上。各个部落因为领地的原因纷纷开战…

【大数据】—量化交易实战案例双均线策略(移动平均线)

声明&#xff1a;股市有风险&#xff0c;投资需谨慎&#xff01;本人没有系统学过金融知识&#xff0c;对股票有敬畏之心没有踏入其大门&#xff0c;今天用另外一种方法模拟炒股&#xff0c;后面的模拟的实战全部用同样的数据&#xff0c;最后比较哪种方法赚的钱多。 量化交易…

解决问题:浏览器中使用必应时提示“cn.bing.com将您的重定向的次数过多“

目录 一、问题分析二、关闭代理三、更新配置文件 一、问题分析 专业问题分析见其它博主的博文&#xff1a;重定向次数过多。 看了其它博文有一定启发&#xff0c;我自己尝试后发现两种解决办法。 二、关闭代理 我自己用的梯子是Clash&#xff0c;参考其他博主的分析&#x…

亚马逊运营专词(二)

1. A页面&#xff1a;亚马逊A页面即图文版商品详情页面&#xff0c;可以通过A页面使用不同的方式来描述商品特征&#xff0c;例如在页面中添加品牌故事、产品图片、产品文字介绍等&#xff0c;进一步完善页面。但目前A页面只对在亚马逊上注册了品牌的商家开放。 2. 跟卖&#x…

【PWN · TcachebinAttack | UAF】[2024CISCN · 华中赛区] note

一道简单的tcache劫持 一、题目 二、思路 存在UAF&#xff0c;libc版本2.31&#xff0c;经典菜单题 1.通过unsorted-bin-attack来leak-libc 2.通过uaf打tcache-bin-attack劫持__free_hook实现getshell 三、EXP from pwn import * context(archamd64,log_leveldebug)ioproce…

阿里提出MS-Diffusion:一键合成你喜爱的所有图像元素,个性化生成新思路!

文本到图像生成模型的最新进展极大地增强了从文本提示生成照片级逼真图像的能力&#xff0c;从而增加了人们对个性化文本到图像应用的兴趣&#xff0c;尤其是在多主题场景中。然而&#xff0c;这些进步受到两个主要挑战的阻碍&#xff1a; 需要根据文本描述准确维护每个参考主题…

ElasticSearch8.X查询DSL语法案例进阶实战

什么是Query DSL Query DSL主要由两部分组成&#xff1a;查询和过滤。 查询部分&#xff1a;用于指定搜索条件和匹配规则。例如&#xff0c;可以使用match查询进行全文检索&#xff0c;term查询进行精确匹配&#xff0c;range查询进行范围匹配等。过滤部分&#xff1a;用于对查…

怎么使用python进行整除取余求幂

怎么使用python进行整除取余求幂&#xff1f; 整除法是//&#xff0c;称为地板除&#xff0c;两个整数的除法仍然是整数。 10//33 3 求模运算是%&#xff0c;相当于mod&#xff0c;也就是计算除法的余数。 5%2 1 求幂运算使用两个连续的*&#xff0c;幂运算符比取反的优先级高…

一码多址与同义词解决方案

随着地址库中的数据不断的丰富&#xff0c;地址库中一码多址和同义词的数据也会越来越多&#xff0c;一码多址和同义词在统一地址管理平台中的概念并不相同。 一码多址指的是多个地址编码相同&#xff0c;例如通过民政地址找到编码&#xff0c;再通过编码找到房产地址描述。 本…