2312skia,16画布
创建SkCanvas
首先,阅读SkCanvasAPI
概述.
Skia
有多个接收SkCanvas
绘图命令的后端.每个后端都有创建SkCanvas
的独特方式.本页给出了每个示例:
光栅化
光栅化
后端将绘画到可由Skia
或客户
管理的内存块
.
推荐用管理画布命令要绘画
内存对象的SkSurface
为Raster
和Ganesh
后端创建
画布.
#include "include/core/SkData.h"
#include "include/core/SkImage.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
void raster(int width, int height, void (*draw)(SkCanvas*), const char* path) {sk_sp<SkSurface> rasterSurface = SkSurface::MakeRasterN32Premul(width, height);SkCanvas* rasterCanvas = rasterSurface->getCanvas();draw(rasterCanvas);sk_sp<SkImage> img(rasterSurface->makeImageSnapshot());if (!img) { return; }sk_sp<SkData> png = SkPngEncoder::Encode(nullptr, img, {});if (!png) { return; }SkFILEWStream out(path);(void)out.write(png->data(), png->size());
}
或,可显式
指定表面
的内存,而不是让Skia
管理它.
#include <vector>
#include "include/core/SkSurface.h"
std::vector<char> raster_direct(int width, int height, void (*draw)(SkCanvas*)) {SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);size_t rowBytes = info.minRowBytes();size_t size = info.getSafeSize(rowBytes);std::vector<char> pixelMemory(size); // 分配内存sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect( info, &pixelMemory[0], rowBytes);SkCanvas* canvas = surface->getCanvas();draw(canvas);return pixelMemory;
}
GPU
GPU
表面必须有管理GPU
环境及纹理和字体
相关缓存的GrContext
对象.GrContexts
与OpenGL
环境或Vulkan
设备一一匹配
.
也即,使用相同的OpenGL
环境或Vulkan
设备渲染到的所有SkSurfaces
都应共享一个GrContext
.Skia
不会为你创建OpenGL
环境或Vulkan
设备.
在OpenGL
模式下,还假定在调用Skia
时,已为当前线程的当前环境
设置了正确的OpenGL
环境.
#include "include/gpu/GrDirectContext.h"#include "include/gpu/gl/GrGLInterface.h"#include "include/gpu/ganesh/gl/GrGLInterface.h"#include "include/core/SkData.h"#include "include/core/SkImage.h"#include "include/core/SkStream.h"#include "include/core/SkSurface.h"void gl_example(int width, int height, void (*draw)(SkCanvas*), const char* path) {// 已经创建了`OpenGL`上下文并绑定了它sk_sp<const GrGLInterface> interface = nullptr;//将`interface`保留为`null`会使`Skia`按特定平台方式,提取当前上下文的`OpenGL`函数的指针.或,可创建自己的`GrGLInterface`,并初化它,以附加到备用`OpenGL`实现或拦截`Skia`的`OpenGL`调用sk_sp<GrDirectContext> context = GrDirectContexts::MakeGL(interface);SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height);sk_sp<SkSurface> gpuSurface(SkSurface::MakeRenderTarget(context.get(), skgpu::Budgeted::kNo, info));if (!gpuSurface) {SkDebugf("SkSurface::MakeRenderTarget returned null\n");return;}SkCanvas* gpuCanvas = gpuSurface->getCanvas();draw(gpuCanvas);sk_sp<SkImage> img(gpuSurface->makeImageSnapshot());if (!img) { return; }// 必须传递非空上下文,以便可以读回和编码`像素`sk_sp<SkData> png = SkPngEncoder::Encode(context.get(), img, {});if (!png) { return; }SkFILEWStream out(path);(void)out.write(png->data(), png->size());}
SKPDF
格式
因为文档
必须包含多页,SkPDF
后端使用SkDocument
而不是SkSurface
.
#include "include/docs/SkPDFDocument.h"#include "include/core/SkStream.h"void skpdf(int width, int height, void (*draw)(SkCanvas*), const char* path) {SkFILEWStream pdfStream(path);auto pdfDoc = SkPDF::MakeDocument(&pdfStream);SkCanvas* pdfCanvas = pdfDoc->beginPage(SkIntToScalar(width), SkIntToScalar(height));draw(pdfCanvas);pdfDoc->close();}
SkPicture
SkPicture
后端使用SkPictureRecorder
而不是SkSurface
.
#include "include/core/SkPictureRecorder.h"#include "include/core/SkPicture.h"#include "include/core/SkStream.h"void picture(int width, int height, void (*draw)(SkCanvas*), const char* path) {SkPictureRecorder recorder;SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width), SkIntToScalar(height));draw(recordingCanvas);sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();SkFILEWStream skpStream(path);// 用`viewer --skps PATH_TO_SKP --slide SKP_FILE`,打开SKP文件picture->serialize(&skpStream);}
空画布
空画布是忽略
所有绘图命令
且无操作
的画布.
#include "include/utils/SkNullCanvas.h"void null_canvas_example(int, int, void (*draw)(SkCanvas*), const char*) {std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();draw(nullCanvas.get()); // 闲着}
SkXPS
(仍在实验阶段)把SkXPS
画布写入XPS
文档.
#include "include/core/SkDocument.h"#include "include/core/SkStream.h"#ifdef SK_BUILD_FOR_WINvoid skxps(IXpsOMObjectFactory* factory; int width, int height, void (*draw)(SkCanvas*), const char* path) {SkFILEWStream xpsStream(path);sk_sp<SkDocument> xpsDoc = SkDocument::MakeXPS(&pdfStream, factory);SkCanvas* xpsCanvas = xpsDoc->beginPage(SkIntToScalar(width), SkIntToScalar(height));draw(xpsCanvas);xpsDoc->close();}#endif
SkSVG
(仍在实验阶段)把SkSVG
画布写入SVG
文档.
#include "include/core/SkStream.h"#include "include/svg/SkSVGCanvas.h"#include "SkXMLWriter.h"void sksvg(int width, int height, void (*draw)(SkCanvas*), const char* path) {SkFILEWStream svgStream(path);std::unique_ptr<SkXMLWriter> xmlWriter( new SkXMLStreamWriter(&svgStream));SkRect bounds = SkRect::MakeIWH(width, height);std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(bounds, xmlWriter.get());draw(svgCanvas.get());}
例
要试用此代码,请使用新的单元测试
,并把这些函数包装
在一起:
#include "include/core/SkCanvas.h"#include "include/core/SkPath.h"#include "tests/Test.h"void example(SkCanvas* canvas) {const SkScalar scale = 256.0f;const SkScalar R = 0.45f * scale;const SkScalar TAU = 6.2831853f;SkPath path;for (int i = 0; i < 5; ++i) {SkScalar theta = 2 * i * TAU / 5;if (i == 0) {path.moveTo(R * cos(theta), R * sin(theta));} else {path.lineTo(R * cos(theta), R * sin(theta));}}path.close();SkPaint p;p.setAntiAlias(true);canvas->clear(SK_ColorWHITE);canvas->translate(0.5f * scale, 0.5f * scale);canvas->drawPath(path, p);}DEF_TEST(FourBackends, r) {raster( 256, 256, example, "out_raster.png" );gl_example( 256, 256, example, "out_gpu.png" );skpdf( 256, 256, example, "out_skpdf.pdf" );picture( 256, 256, example, "out_picture.skp");}
画布概述
绘图环境
细节
SkCanvas
是Skia
的绘图环境
.它知道直接在哪绘图
(即屏幕外像素
的屏幕
位置),并维护一堆矩阵和剪切
.
但注意,与其他API
(如postscript,cairo
或awt
)中的类似环境不同,Skia
不会在环境
中存储其他(如颜色,笔大小
)绘图属性
.相反,在每次
绘画调用中,通过SkPaint
显式指定它们.
确切地说,画笔
而不是画布
,描述绘画
的颜色和风格
.
首先,可能想要擦除
整个画布.可绘画巨大
矩形来完成,但有更简单
方法.
void draw(SkCanvas* canvas) {SkPaint paint;paint.setColor(SK_ColorWHITE);canvas->drawPaint(paint);}
这(当然,尊重当前剪切)指定
绘画用的颜色或着色器
(和xfermode
),并填充整个画布
.如果画笔
中有个着色器
,则它也会遵循画布
上的当前矩阵
(见SkShader
).
如果(用可选的xfermode
)只想绘画
个颜色,你可直接调用drawColor()
,这样就不必赋值
画笔了.
void draw(SkCanvas* canvas) {canvas->drawColor(SK_ColorWHITE);}
所有其他绘画API
类似,都以画笔
参数结尾.
在某些
调用中,传递画笔
的指针,而不是引用
.这时,paint
参数可能为null
.其他时候,必需要有paint
参数.
画笔概览
每当你在Skia
中画笔
某些内容时,想要指定颜色
,或如何与背景
混合,或使用的风格或字体
,都可在画笔
中指定这些属性.
与SkCanvas
不同,画笔
不维护内部状态栈
(即画笔上不保存/恢复
).然而,画笔
是轻量
的,因此客户可创建和维护
多个用途不同的画笔
对象.
从画布
状态中,分解出所有这些颜色和风格
属性,并转换为(多个
)画笔
对象中,因为只需维护矩阵
和剪切
设置栈,可更加高效的保存/恢复画布
.
可显示三个不同
画笔,每种画笔
都按以不同的风格设置.现在,调用者
可自由地混合
这些画笔
,可原样使用它们,也可在绘图
过程中修改它们.
除了颜色,描边和文本值
等简单属性外,画笔还支持特效
.它是绘图管线
不同方面的子类
,引用画笔
时(每个子类
都按引用计数
),调用它以覆盖
绘图管线的某些部分
.
如,要用渐变
而不是单色
画笔,请为画笔
指定SkShader
.
现在,使用该画笔的内容都使用调用MakeLinear()
中指定的渐变画笔
.返回的着色器
对象是引用计数
的.每当赋值着色
器等特效对象
给画笔
时,画笔都会增加引用计数
.
为了平衡,上面赋值给画笔后,在着色器
上马上调用unref()
.现在,画笔
是该着色器的唯一"物主"
,当画笔
出域或为其赋值另一个着色器(或null
)时,它自动在着色器
上调用unref()
.
有6种类型的特效可赋值
给画笔:
1,SkPathEffect
,在生成α
掩码(如破折号)修改几何路径
2,SkRasterizer
,合成
自定义掩码图层(如阴影
)
3,SkMaskFilter
,在着色及绘画前修改α
掩码(如模糊)
4,SkShader
:如渐变
(线性,径向,扫描
),位图模式(夹,重复,镜像
)
5,SkColorFilter
,在混合
前修改源颜色
(如颜色矩阵
)
6,SkBlendMode
:如porter-duff
传输模式,混合模式等
画笔
还有SkTypeface
的引用.字体
表示来测量和绘画
文本的特定字体风格
.画笔不仅可绘画
文本,还可测量
文本.
paint.measureText(...);paint.getTextBounds(...);paint.textToGlyphs(...);paint.getFontMetrics(...);
SkBlend
模式
以下示例演示了Skia
的所有标准混合模式
.此例中,源
是有水平α
渐变的纯洋红色
,目标为有垂直α
渐变的纯青色
.
SkShader
定义了几个着色器(除了已提到的线性渐变):
1,位图
着色器
2,径向渐变
着色器
3,两点锥形
渐变着色器
4,扫描
渐变着色器
5,分形
噪声着色器
6,湍流
噪声着色器
7,合成
着色器
SkMask
过滤器
1,模糊
掩码过滤器
SkColor
过滤器
ColorMatrix
颜色过滤器
颜色表
颜色过滤器
SkPathEffect
1,SkPath2DPathEffect
:用矩阵
定义晶格,标记指定路径
以填充
形状.
2,SkLine2DPathEffect
:路径是要描边
而不是要填充
的直线路径的SkPath2DPathEffect
的特例.
3,SkPath1DPathEffect
:通过复制指定路径
沿着画笔
路径,创建
类似破折号
的特效.
4,SkCornerPathEffect
:一个可变形尖角
的特效(如圆角).
5,SkDashPathEffect
:实现破折号
的路径特效.
6,SkDiscretePathEffect
:此路径特效把路径切成离散段
,并随机替换它们.
7,SkComposePathEffect
:先应用内部pathEffect
,再外部pathEffect
(即outer(inner(path))
)的pathEffect
特效.
8,SkSumPathEffect
:按如下应用两个特效的pathEffect
特效:
sequence (first(path) + second(path)).
相关文章:
2312skia,16画布
创建SkCanvas 首先,阅读SkCanvasAPI概述. Skia有多个接收SkCanvas绘图命令的后端.每个后端都有创建SkCanvas的独特方式.本页给出了每个示例: 光栅化 光栅化后端将绘画到可由Skia或客户管理的内存块. 推荐用管理画布命令要绘画内存对象的SkSurface为Raster和Ganesh后端创建画…...

mysql文本类型的最大长度限制
mysql支持很多类型,不同的文本有不同的长度限制。可以根据实际需要进行选择。 TINYBLOB, TINYTEXT L 1 bytes, where L < 2^8 (255 Bytes) BLOB, TEXT L 2 bytes, where L < 2^16 (64 Kilobytes) MEDIUMBLOB, MEDIUMTEXT L 3 b…...

ASP.NET《数据库原理及应用技术》课程指导平台的开发
1.1 系统设计目标 研制《数据库原理及应用技术》课程指导平台在功能上可以满足网络课堂教学活动的需要,在Internet上实现教学活动的各个环节。系统的基本设计原则有:先进性与方便性原则、功能实用性原则、开放性与可扩展性原则等。系统设计时采用较好的…...

OSHI-操作系统和硬件信息库
文章目录 引言一、快速入门1.1 OSHI的简介1.2 引入依赖1.3 涉及的包(package)1.4 涉及的核心类 二、操作系统信息:OperatingSystem2.1 总揽2.2 文件系统信息:FileSystem2.3 网络参数信息:NetworkParams2.4 进程信息&am…...

基于Java SSM框架+Vue实现企业公寓后勤管理系统项目【项目源码+论文说明】计算机毕业设计
基于java的SSM框架Vue实现企业宿舍后勤管理网站演示 摘要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所…...

stm32mp157和imx6ull在设备树节点上设置ap3216c的主要区别
stm32mp157和imx6ull在设备树节点上设置ap3216c的主要区别是,它们使用的不同的硬件架构和不同的设备树格式。以下是两者之间的差异: 硬件架构:stm32mp157是基于ARM Cortex-M4内核的微控制器,而imx6ull则是基于ARM Cortex-A7内核的…...
网工学习6-配置和管理 VLAN
6.1VLAN概念 1> 什么是 VLAN? VLAN 是一种在交换机上划分逻辑网段的二层技术。 2> 为什么要通过交换机划分网段? ① 因为交换机的端口密度比路由器高,并且价格比路由器低,所以组网成本更低。 ② 因为交换机划分网段比…...
MySQL库与表的备份
库的备份 备份 语法 mysqldump -P3306 -u root -p 密码 -B 数据库名 > 数据库备份存储的文件路径 例 mysqldump -P3306 -u root -p123456 -B mytest > D:/mytest.sql 注意 这是在linux命令行下。 还原 语法 scource 数据库文件路径 例 source D:/mysql-5.7.22/mytest.s…...
Python核心编程之基础内功
目录 一、语句和语法 1、 注释( # ) 2、继续( \ ) 3、多个语句构成代码组(:):...

GPT4-Turbo技术原理研发现状及未来应用潜力分析报告
今天分享的是GPT4-Turb系列深度研究报告:《GPT4-Turbo技术原理研发现状及未来应用潜力分析报告》。 (报告出品方:深度行业分析研究) 报告共计:46页 图像理解能力提升:三大视觉学习方法 为打造视觉大模…...

为什么 SQL 不适合图数据库
背景 “为什么你们的图形产品不支持 SQL 或类似 SQL 的查询语言?” 过去,我们的一些客户经常问这个问题,但随着时间的推移,这个问题变得越来越少。 尽管一度被忽视,但图数据库拥有无缝设计并适应其底层数据结构的查询…...

【Rust日报】2023-12-02 深度学习框架 Burn 发布 v0.11.0
深度学习框架 Burn 发布 v0.11.0 深度学习框架 Burn 发布 v0.11.0,新版本引入了自动内核融合(Kernel Fusion)功能,大大提升了访存密集型(memory-bound)操作的性能。同时宣布成立 Tracel AI (https://tracel…...

MySQL性能调优-1-实际优化案例
关于SQL优化的思路,一般都是使用执行计划看看是否用到了索引,主要可能有两大类情况: 对业务字段建立了二级联合索引,但是MySQL错误地觉得走主键聚族索引全表扫描效率更高,而没有走二级索引 走二级索引,但…...

JavaScript空值合并运算符
The Nullish Coalescing Operator(空值合并运算符)是一种 JavaScript 的新运算符,用于解决默认值设定中存在的一些问题。它的语法为 ??(两个问号),表示当左侧的操作数为 null 或 undefined 时,…...
Spring Boot 集成 spring security 01
一、导入依赖(pom.xml) <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&qu…...
C 编程中使用字符串
理解字符串: C 中的字符串是使用字符数组来操作的。数组中的每个字符对应字符串的一个元素,字符串的结尾由空字符(\0)标记。这个空字符至关重要,因为它表示字符串的结尾,并允许函数确定字符串在内存中的结…...

【GD32307E-START】04 使用TinyMaix进行手写数字识别
【GD32307E-START】04 使用TinyMaix进行手写数字识别 参考博客 【GD32F427开发板试用】使用TinyMaix进行手写数字识别 https://blog.csdn.net/weixin_47569031/article/details/129009839 软硬件平台 GD32F307E-START Board开发板GCC Makefile TinyMaix简介 TinyMaix是国…...

qt-C++笔记之识别点击鼠标右键、点击位置以及Qt坐标系详解
qt-C笔记之识别点击鼠标右键、点击位置以及Qt坐标系详解 code review! 文章目录 qt-C笔记之识别点击鼠标右键、点击位置以及Qt坐标系详解1.示例运行2.event->pos();详解3.event->pos()的坐标系原点4.Qt中的坐标系详解5.QMainWindow::mousePressEvent(event);详解 1.示例…...

小程序开发平台源码系统:搭建新的商业体系 附带完整的搭建教程
小程序开发平台源码系统是在移动互联网快速发展的背景下诞生的。随着微信小程序的普及,越来越多的人开始关注小程序的开发与运营。然而,对于很多初学者和小型企业来说,开发一个小程序需要专业的技术知识和大量的时间投入,这无疑是…...
css3新增的伪类有哪些?
CSS3新增的伪类有: :first-of-type,选择属于其父元素的特定类型的第一个子元素。:last-of-type,选择属于其父元素的特定类型的最后一个子元素。:only-of-type,选择属于其父元素的特定类型的唯一子元素。:only-child,选…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
Docker、Wsl 打包迁移环境
电脑需要开启wsl2 可以使用wsl -v 查看当前的版本 wsl -v WSL 版本: 2.2.4.0 内核版本: 5.15.153.1-2 WSLg 版本: 1.0.61 MSRDC 版本: 1.2.5326 Direct3D 版本: 1.611.1-81528511 DXCore 版本: 10.0.2609…...