【SkiaSharp绘图13】SKCanvas方法详解(二)填充颜色、封装对象、高性能绘制、点(集)(多段)线、圆角矩形、Surface、沿路径绘制文字

文章目录

  • SKCanvas方法
    • DrawColor 填充颜色
    • DrawDrawable 绘制封装对象
    • DrawImage 高性能绘制图像
    • SKBitmap与SKImage对比
    • DrawPicture 绘制图像
      • SKPicture
    • DrawPoint / DrawPoints 绘制点
    • DrawRoundRect/DrawRoundRectDifference绘制圆角矩形
    • DrawSurface 绘制Surface
    • DrawTextOnPath沿路径绘制文字

SKCanvas方法

DrawColor 填充颜色

public void DrawColor (SkiaSharp.SKColor color, SkiaSharp.SKBlendMode mode = SkiaSharp.SKBlendMode.Src);
public void DrawColor (SkiaSharp.SKColorF color, SkiaSharp.SKBlendMode mode = SkiaSharp.SKBlendMode.Src);

使用指定颜色和混合方式填充当前裁切区域。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
{canvas.DrawColor(SKColors.LightGreen, SKBlendMode.Src);canvas.ClipRect(new SKRect(100, 100, 300, 200));//将颜色填充当前裁切区域canvas.DrawColor(SKColors.Blue, SKBlendMode.SrcOver);paint.Color = SKColors.Red;paint.TextSize = 24;canvas.DrawText($"DrawColor", 95, 150, paint);
}

使用亮绿填充整个区域,修改裁切区域后,再次填充为蓝色。

DrawColor

DrawDrawable 绘制封装对象

public void DrawDrawable (SkiaSharp.SKDrawable drawable, float x, float y);
public void DrawDrawable (SkiaSharp.SKDrawable drawable, SkiaSharp.SKPoint p);
public void DrawDrawable (SkiaSharp.SKDrawable drawable, ref SkiaSharp.SKMatrix matrix);

绘制一个封装了绘制业务的对象。

  1. 封装一个绘制笑脸的业务逻辑。
/// <summary>
/// 封闭一个绘制笑脸对象
/// </summary>
public class FaceDrawable:SKDrawable
{protected override void OnDraw(SKCanvas canvas){using (var paint = new SKPaint()){paint.Color = SKColors.LightGreen;canvas.DrawCircle(100, 100, 100, paint);paint.Color = SKColors.Red;paint.IsStroke = true;canvas.DrawCircle(60,80,25, paint);canvas.DrawCircle(140, 80, 25, paint);canvas.DrawArc(new SKRect(75, 90, 125, 130), 45, 90, false, paint);}                }
}
  1. 重复横、列多次绘制。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);var drawable = new FaceDrawable();using (var paint = new SKPaint())
{//多次绘制一组相同的对象var bounds=drawable.Bounds;for (float x = 0; x < this.Width - bounds.Width; x += bounds.Width){for(float y = 0; y < this.Height - bounds.Height; y += bounds.Height){canvas.DrawDrawable(drawable,x,y);}}
}

DrawDrawable

DrawImage 高性能绘制图像

public void DrawImage (SkiaSharp.SKImage image, SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint = default);
public void DrawImage (SkiaSharp.SKImage image, SkiaSharp.SKRect dest, SkiaSharp.SKPaint paint = default);
public void DrawImage (SkiaSharp.SKImage image, SkiaSharp.SKRect source, SkiaSharp.SKRect dest, SkiaSharp.SKPaint paint = default);
public void DrawImage (SkiaSharp.SKImage image, float x, float y, SkiaSharp.SKPaint paint = default);

相比SKBitmap,性能更优,但SKImage内容不可变。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);if (skBmp == null)
{skBmp = SKBitmap.Decode(@"Images\AIWoman.png");skBmp = skBmp.Resize(new SKSizeI(350, 350), SKFilterQuality.High);
}
if (skImg == null) skImg = SKImage.FromBitmap(skBmp);const int DrawCount = 1000;
using (var paint = new SKPaint())
{paint.IsAntialias = true;paint.FilterQuality = SKFilterQuality.High;paint.TextSize = 24;for (int i = 0; i < 2; i++){count += 1;var sw = Stopwatch.StartNew();for (int j = 0; j < DrawCount; j++){if (count % 2 == 0){canvas.DrawImage(skImg, 400, 20, paint);}else{canvas.DrawBitmap(skBmp, 0, 20, paint);}}sw.Stop();if (count % 2 == 0){canvas.DrawText($"DrawImage {DrawCount}times:{sw.ElapsedMilliseconds}ms", 400, 400, paint);}else{canvas.DrawText($"DrawBitmap {DrawCount}times:{sw.ElapsedMilliseconds}ms", 0, 400, paint);}}
}

对比多次使用SKBitmap与SKImage绘制同一幅图像。
DrawImage

SKBitmap与SKImage对比

SKBitmap

  1. 可变性
    SKBitmap 是可变的,允许对像素进行直接的读写操作。这使得它非常适合需要频繁修改图像内容的情况。

  2. 内存管理
    SKBitmap 的内存是可管理的,这意味着你可以控制它的分配和释放。开发者需要注意内存管理以防止内存泄漏。

  3. 使用场景
    适用于需要直接处理像素数据的场景,如图像编辑、动态生成图像等。

SKImage

  1. 不可变性
    SKImage 是不可变的,一旦创建后其内容无法更改。这使得它非常适合用于高效的图像显示和传递。

  2. 内存管理
    SKImage 通常是通过图形硬件加速的,因此在性能上优于 SKBitmap。内存管理更为自动化,不需要开发者显式地管理。

  3. 使用场景
    适用于图像渲染、显示和传输,如绘制在屏幕上、保存为文件等。

DrawPicture 绘制图像

public void DrawPicture (SkiaSharp.SKPicture picture, SkiaSharp.SKPaint paint = default);
public void DrawPicture (SkiaSharp.SKPicture picture, ref SkiaSharp.SKMatrix matrix, SkiaSharp.SKPaint paint = default);
public void DrawPicture (SkiaSharp.SKPicture picture, SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint = default);
public void DrawPicture (SkiaSharp.SKPicture picture, float x, float y, SkiaSharp.SKPaint paint = default);

SKPicture

主要用于记录绘图命令以便在以后重用。

  1. 高效的重绘

    • SKPicture 可以记录一次绘图操作的所有命令,然后在需要的时候进行重放。这样可以避免每次重绘时重新执行复杂的绘图逻辑,提高绘图的效率。
  2. 减少CPU开销

    • 在一些复杂的绘图操作中,通过记录绘图命令并重放,可以减少CPU的计算开销,因为重放绘图命令比重新执行绘图逻辑所需的计算量更小。
  3. 方便的图形内容重用

    • SKPicture 允许将绘图命令记录下来并在不同的地方重用。例如,可以在多个视图中重用相同的图形内容,而不需要每次都重新绘制。
  4. 支持多线程绘图

    • SKPicture 的记录和重放机制使得绘图命令可以在后台线程中生成,然后在主线程中重放。这有助于实现更流畅的用户界面和更好的响应性。
  5. 简化复杂场景的处理

    • 对于一些复杂的场景绘制,可以先将场景绘制到 SKPicture 中,然后在需要的时候重放这个 SKPicture。这使得处理复杂场景变得更加简单和直观。
var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);if (skPic == null)
{using (var recorder = new SKPictureRecorder()){using (var picCanvas = recorder.BeginRecording(SKRect.Create(400, 400)))using (var paint = new SKPaint()){paint.Color = SKColors.Red;paint.IsStroke = true;picCanvas.DrawCircle(60, 60, 50, paint);paint.IsStroke = false;paint.Color = SKColors.LightGreen;picCanvas.DrawRoundRect(100, 100, 350, 350, 50, 50, paint);}skPic = recorder.EndRecording();}
}using(var paint=new SKPaint())
{canvas.DrawPicture(skPic, paint);canvas.Translate(350, 350);canvas.DrawPicture(skPic, paint);
}

使用SKPictureRecorder生成SKPicture。
DrawPicture

DrawPoint / DrawPoints 绘制点

public void DrawPoint (SkiaSharp.SKPoint p, SkiaSharp.SKColor color);
public void DrawPoint (SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint);
public void DrawPoint (float x, float y, SkiaSharp.SKColor color);
public void DrawPoint (float x, float y, SkiaSharp.SKPaint paint);
public void DrawPoints (SkiaSharp.SKPointMode mode, SkiaSharp.SKPoint[] points, SkiaSharp.SKPaint paint);

绘制点和点集

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
{canvas.DrawPoint(50,50,SKColors.Red);canvas.DrawPoint(100, 50, SKColors.Blue);paint.StrokeWidth = 10;paint.Color = SKColors.Red;canvas.DrawPoint(50, 100, paint);paint.Color = SKColors.Blue;paint.StrokeCap = SKStrokeCap.Round;canvas.DrawPoint(100, 100, paint);var points = new SKPoint[] {new SKPoint(200,20),new SKPoint(400,20),new SKPoint(400,120),new SKPoint(200,120),new SKPoint(200,160),new SKPoint(300,160)};canvas.DrawPoints(SKPointMode.Points, points, paint);paint.Color = SKColors.Green;canvas.Translate(0, 200);canvas.DrawPoints(SKPointMode.Lines, points, paint);paint.Color = SKColors.Red;canvas.Translate(0, 200);canvas.DrawPoints(SKPointMode.Polygon, points, paint);
}

可以绘制点集、线段(两个点连一条线),多段线
DrawPoint/DrawPoints

DrawRoundRect/DrawRoundRectDifference绘制圆角矩形

public void DrawRoundRect (SkiaSharp.SKRoundRect rect, SkiaSharp.SKPaint paint);
public void DrawRoundRect (SkiaSharp.SKRect rect, SkiaSharp.SKSize r, SkiaSharp.SKPaint paint);
public void DrawRoundRect (SkiaSharp.SKRect rect, float rx, float ry, SkiaSharp.SKPaint paint);
public void DrawRoundRect (float x, float y, float w, float h, float rx, float ry, SkiaSharp.SKPaint paint);
public void DrawRoundRectDifference (SkiaSharp.SKRoundRect outer, SkiaSharp.SKRoundRect inner, SkiaSharp.SKPaint paint);

绘制圆角矩形及两个圆角矩形之间的区域。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
using (var txtPaint = new SKPaint())
{txtPaint.IsAntialias = true;txtPaint.Color = SKColors.Red;txtPaint.TextSize = 18;paint.IsAntialias = true;paint.IsStroke = true;paint.StrokeWidth = 2;var rect = new SKRect(50, 50, 250, 150);canvas.DrawRoundRect(rect, new SKSize(20, 20), paint);canvas.DrawText($"DrawRoundRect, rx=20,ry=20", 50, 180, txtPaint);paint.Color = SKColors.Red;canvas.Translate(250, 0);canvas.DrawRoundRect(rect, new SKSize(50, 20), paint);canvas.DrawText($"DrawRoundRect, rx=50,ry=20", 50, 180, txtPaint);paint.Style = SKPaintStyle.Fill;canvas.Translate(0, 100);// 定义外部圆角矩形var outerRect = new SKRoundRect(new SKRect(100, 100, 500, 400), 50, 50);// 定义内部圆角矩形var innerRect = new SKRoundRect(new SKRect(120, 120, 480, 380), 30, 50);canvas.DrawRoundRectDifference(outerRect, innerRect, paint);}

绘制不同圆角的圆角矩形,及两个圆角矩形之间区域。

在这里插入图片描述

DrawSurface 绘制Surface

public void DrawSurface (SkiaSharp.SKSurface surface, SkiaSharp.SKPoint p, SkiaSharp.SKPaint paint = default);
public void DrawSurface (SkiaSharp.SKSurface surface, float x, float y, SkiaSharp.SKPaint paint = default);

将Surface绘制到当前画布上。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);using (var paint = new SKPaint())
{using (var skBmp = new SKBitmap(400, 400))using (var surfaceA = SKSurface.Create(skBmp.Info, skBmp.RowBytes))using (var canvasA = surfaceA.Canvas)using (var paintA = new SKPaint()){paintA.IsAntialias = true;paintA.Color = SKColors.Red;paintA.IsStroke = true;canvasA.Clear(SKColors.White);canvasA.DrawRect(20, 20, 300, 120, paintA);canvasA.DrawCircle(200, 200, 100, paintA);canvas.DrawSurface(surfaceA, 50, 50);canvas.DrawText($"DrawSurface", 50, 350, paint);canvas.DrawSurface(surfaceA, 350, 350);canvas.DrawText($"DrawSurface", 350,650, paint);}
}

DrawSurface

DrawTextOnPath沿路径绘制文字

public void DrawTextOnPath (string text, SkiaSharp.SKPath path, SkiaSharp.SKPoint offset, bool warpGlyphs, SkiaSharp.SKPaint paint);
public void DrawTextOnPath (string text, SkiaSharp.SKPath path, SkiaSharp.SKPoint offset, SkiaSharp.SKPaint paint);
public void DrawTextOnPath (string text, SkiaSharp.SKPath path, float hOffset, float vOffset, SkiaSharp.SKPaint paint);

定义一个路径,可使文字基线沿着路径还不是普通的直线。

var canvas = e.Surface.Canvas;
var info = e.Info;
canvas.Clear(SKColors.White);string text = $"SkiaSharp可以直接绘制一段绕着路径(如曲线)行走的文字,是不是很Cool!";
var path = new SKPath();path.MoveTo(50, 50); // 起始点
path.CubicTo(250, 400, 550, 100, 750, 600); // 三次贝塞尔曲线   
var pathMeasure = new SKPathMeasure(path, false);using (var paint = new SKPaint())
{paint.IsAntialias = true;paint.Color = SKColors.Red;paint.TextSize = 22;if (timer == null){var pathLength = pathMeasure.Length / 2;hOffset = pathLength;timer = new System.Windows.Forms.Timer();timer.Interval = 30;timer.Tick += (o, t) =>{hOffset -= 2;if (hOffset <= -pathLength){hOffset = pathLength;}this.TNTechImageBox.Invalidate();};timer.Start();}paint.Typeface = SKTypeface.FromFamilyName("宋体");var vOffset = -paint.TextSize / 2; // 垂直偏移量,使文本中心对齐路径               canvas.DrawTextOnPath(text, path, hOffset, vOffset, paint);paint.IsStroke = true;canvas.DrawPath(path, paint);}
  1. 定义一段贝赛尔曲线
  2. 定义一段文字
  3. 定义一个定时器
  4. 使文字沿着曲线动态绘制。

DrawTextOnPath

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android - 利用 jitpack 免费发布闭源 aar

一、简述 目前(Android/java) library 的主要发布仓库有 MavenCentral 和 jitpack,我之前也对这两种仓库的发布流程做了详细介绍: 发布至 MavenCentral: https://juejin.cn/post/6953598441817636900发布至 jitpack: https://juejin.cn/post/7040733114506674183#heading-…

C# 入门—实现 Hello, World!

目录 一、.net 平台与.NET Framework框架 .NET Framework的构成 CLR&#xff1a;公共语言运行库 FCL&#xff1a;框架类库 WinForms ASP.NET ADO.NET WPF WCF WF LINQ Entity Framework Parallel LINQ 二、.net 能干什么 .net 两种交互模式 .net 能干什么 .net …

优化模型验证30:多车场车辆路径问题模型及Gurobipy验证

目录 1 数学模型 1.1 用到的符号集合 1.2 模型公式 2 模型验证代码 2.1 Gurobipy代码 2.2 结果可视化 多车场车辆路径问题的定义:大型的物流公司拥有多个车场,而每个车场都有若干车辆用于配送,决策者需要根据客户的所在位置,将客户分配到合适的车场和车辆中。 1 数学模…

c++静态成员变量和静态成员函数

1&#xff09;C入门级小知识&#xff0c;分享给将要学习或者正在学习C开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 我们可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成…

华为云鲲鹏架构docker部署2048小游戏

华为云鲲鹏架构docker部署2048小游戏 1. 鲲鹏架构ESC2. 配置docker3. 上传2048镜像4. 删除容器,镜像 1. 鲲鹏架构ESC 2. 配置docker 安装dockeryum -y install docker开机启动 systemctl enable docker启动docker服务 systemctl start docker查询docker的运行版本 docker -v3…

注意力机制之ECA-Net:Efficient Channel Attention for Deep Convolutional Neural Network

论文link&#xff1a;link code&#xff1a;code 1.摘要 近年来&#xff0c;通道注意机制被证明在改善深层卷积神经网络&#xff08;CNN&#xff09;的性能方面提供了巨大的潜力。然而现有的大多数方法都致力于开发更复杂的注意模块以获得更好的性能&#xff0c;这不可避免地增…

1.linux操作系统CPU负载

目录 概述CPU平均负载查看平均负载结束 概述 CPU 使用率 和CPU 平均使用率。 CPU平均负载 单位时间内系统处于 [可运行状态] 和 [不可中断状态] 的平均进程数&#xff0c;就是平均活跃进程数&#xff0c;和CPU使用率并没有直接关系 可运行状态 正在使用CPU或者正等待CPU的进…

从头开始构建一个小规模的文生视频模型

OpenAI 的 Sora、Stability AI 的 Stable Video Diffusion 以及许多其他已经发布或未来将出现的文本生成视频模型&#xff0c;是继大语言模型 (LLM) 之后 2024 年最流行的 AI 趋势之一。 在这篇博客中&#xff0c;作者将展示如何将从头开始构建一个小规模的文本生成视频模型&a…

C# 实现websocket双向通信

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C# &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff…

AWT的菜单组件

AWT的菜单组件 前言一、菜单组件的介绍常见的菜单相关组件常见菜单相关组件集成体系图菜单相关组件使用小要点 二、AWT菜单组件的代码示例示例一示例二实现思路 前言 推荐一个网站给想要了解或者学习人工智能知识的读者&#xff0c;这个网站里内容讲解通俗易懂且风趣幽默&…

如何使用sr2t将你的安全扫描报告转换为表格格式

关于sr2t sr2t是一款针对安全扫描报告的格式转换工具&#xff0c;全称为“Scanning reports to tabular”&#xff0c;该工具可以获取扫描工具的输出文件&#xff0c;并将文件数据转换为表格格式&#xff0c;例如CSV、XLSX或文本表格等&#xff0c;能够为广大研究人员提供一个…

MySQL详细介绍:开源关系数据库管理系统的魅力

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

理解GPT2:无监督学习的多任务语言模型

目录 一、背景与动机 二、卖点与创新 三、几个问题 四、具体是如何做的 1、更多、优质的数据&#xff0c;更大的模型 2、大数据量&#xff0c;大模型使得zero-shot成为可能 3、使用prompt做下游任务 五、一些资料 一、背景与动机 基于 Transformer 解码器的 GPT-1 证明…

容器技术-docker4

一、docker资源限制 在使用 docker 运行容器时&#xff0c;一台主机上可能会运行几百个容器&#xff0c;这些容器虽然互相隔离&#xff0c;但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制&#xff0c;那么容器之间会互相影响&#xff0c;小的来说…

【Spring】DAO 和 Repository 的区别

DAO 和 Repository 的区别 1.概述2.DAO 模式2.1 User2.2 UserDao2.3 UserDaoImpl 3.Repository 模式3.1 UserRepository3.2 UserRepositoryImpl 4.具有多个 DAO 的 Repository 模式4.1 Tweet4.2 TweetDao 和 TweetDaoImpl4.3 增强 User 域4.4 UserRepositoryImpl 5.比较两种模式…

【机器学习】机器学习的重要技术——生成对抗网络:理论、算法与实践

引言 生成对抗网络&#xff08;Generative Adversarial Networks, GANs&#xff09;由Ian Goodfellow等人在2014年提出&#xff0c;通过生成器和判别器两个神经网络的对抗训练&#xff0c;成功实现了高质量数据的生成。GANs在图像生成、数据增强、风格迁移等领域取得了显著成果…

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上&#xff0c;或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景&#xff1a; 表单…

ros笔记01--初次体验ros2

ros笔记01--初次体验ros2 介绍安装ros2测试验证ros2说明 介绍 机器人操作系统(ROS)是一组用于构建机器人应用程序的软件库和工具。从驱动程序和最先进的算法到强大的开发者工具&#xff0c;ROS拥有我们下一个机器人项目所需的开源工具。 当前ros已经应用到各类机器人项目开发中…

【Matlab 六自由度机器人】机器人动力学之推导拉格朗日方程(附MATLAB机器人动力学拉格朗日方程推导代码)

【Matlab 六自由度机器人】机器人动力学概述 近期更新前言正文一、拉格朗日方程的推导1. 单自由度系统2. 单连杆机械臂系统3. 双连杆机械臂系统 二、MATLAB实例推导1. 机器人模型的建立2. 动力学代码 总结参考文献 近期更新 【汇总】 【Matlab 六自由度机器人】系列文章汇总 …

Elasticsearch 第四期:搜索和过滤

序 2024年4月&#xff0c;小组计算建设标签平台&#xff0c;使用ES等工具建了一个demo&#xff0c;由于领导变动关系&#xff0c;项目基本夭折。其实这两年也陆陆续续接触和使用过ES&#xff0c;两年前也看过ES的官网&#xff0c;当时刚毕业半年多&#xff0c;由于历史局限性导…