2312skia,16画布

创建SkCanvas

首先,阅读SkCanvasAPI概述.
Skia有多个接收SkCanvas绘图命令的后端.每个后端都有创建SkCanvas的独特方式.本页给出了每个示例:

光栅化

光栅化后端将绘画到可由Skia客户管理的内存块.
推荐用管理画布命令要绘画内存对象的SkSurfaceRasterGanesh后端创建画布.


#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对象.GrContextsOpenGL环境或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");}

画布概述

绘图环境

细节

SkCanvasSkia绘图环境.它知道直接在哪绘图(即屏幕外像素屏幕位置),并维护一堆矩阵和剪切.

但注意,与其他API(如postscript,cairoawt)中的类似环境不同,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)).

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

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

相关文章

用CHAT如何写教研室工作总结?

问CHAT&#xff1a;写一份教研室工作总结 CHAT回复&#xff1a;以下是一个教研室工作总结的大纳&#xff0c;具体内容需要根据你们教研室的实际情况进行填充和修改。 教研室XXXX年度工作总结 1. 引言&#xff1a;简要介绍本年度工作总结的目的和主题。 2. 教育教学工作&…

Java核心知识点整理大全24-笔记

目录 22. 数据结构 22.1.1. 栈&#xff08;stack&#xff09; 22.1.2. 队列&#xff08;queue&#xff09; 22.1.3. 链表&#xff08;Link&#xff09; 22.1.4. 散列表&#xff08;Hash Table&#xff09; 22.1.5. 排序二叉树 22.1.5.1. 插入操作 22.1.5.2. 删除操作 2…

知识点滴 - 什么是半透膜和渗透压

半透膜和渗透作用 1748年的一天&#xff0c;法国物理学家诺勒为了改进酒的制作水平&#xff0c;设计了这样一个试验&#xff1a;在一个玻璃圆筒中装满酒精&#xff0c;用猪膀胱封住&#xff0c;然后把圆筒全部浸在水中。当他正要做下一步的工作时&#xff0c;突然发现&#xff…

DDOS攻击为何永不过时?

文章目录 一、DOS二、DDOS三、如何防范DDOS 1.可以过滤IP地址2.增加设备3.在骨干节点配置防火墙4.开启过滤5.配置DNS抗攻击6.白帽团队 四、白帽子 为什么二十年前中国红客们就在用的DDOS攻击直到现在还依然是黑客们最爱的攻击方法&#xff1f;二十年前的攻击技术为什么还不过…

Day12——集合

1.集合 在内存层面需要针对于多个数据进行存储。此时可以考虑的容器有&#xff1a;数组、集合类。 数组存储多个数据方面的特点&#xff1a; 数组一旦初始化&#xff0c;其长度就是确定的。数组中的多个元素是依次紧密排列的&#xff0c;有序的&#xff0c;可重复的。数组一…

mysql数据库常见函数(时间函数)

一、mysql日期函数 ADDDATE(d,n) &#xff1b; 计算起始日期 d 加上 n 天的日期 代码如下&#xff08;示例&#xff09;&#xff1a; SELECT ADDDATE("2023-11-11", INTERVAL 31 DAY); ->2023-12-12ADDTIME(t,n)&#xff1b; n 是一个时间表达式&#xff0c;时间…

基于Java SSM框架+Vue实现教学视频点播网站项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架Vue实现教学视频点播网站演示 摘要 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多学院的之中&#xff0c;随之就产生了“视频点播系统”&#xff0c;这样就让视频点播系统更加方便简单。 对于…

Java 学习之多态

多态的概念 多态 晚绑定。 所谓多态&#xff0c;就是父类型的引用可以指向子类型的对象&#xff0c;或者接口类型的引用可以指向实现该接口的类的实例。 不要把函数重载理解为多态。因为多态是一种运行期的行为&#xff0c;不是编译期的行为。 多态&#xff1a;父类型的引用可…

java源码-Java方法的定义和使用详解

1、 方法定义 如果我们想定义一个方法&#xff0c;基本语法如下&#xff1a; 修饰符&#xff1a;方法的修饰符是可选的&#xff0c;用于定义该方法的访问类型&#xff0c;可用的修饰符包括public/private/protected/默认的。 返回值&#xff1a;方法可以有返回值&#xff0c;…

线程中出现异常的处理

目录 前言 正文 1.线程出现异常的默认行为 2.使用 setUncaughtExceptionHandler() 方法进行异常处理 3.使用 setDefaultUncaughtExceptionHandler() 方法进行异常处理 4.线程组内处理异常 5.线程异常处理的优先性 总结 前言 在紧密交织的多线程环境中&#xff0c;异…

解决:ValueError: binary mode doesn‘t take an encoding argument

解决&#xff1a;ValueError: binary mode doesn‘t take an encoding argument 文章目录 解决&#xff1a;ValueError: binary mode doesn‘t take an encoding argument背景报错问题报错翻译报错位置代码报错原因解决方法方法一方法二今天的分享就到此结束了 背景 在使用之前…

USART的PAL库编程

USART驱动的工作原理 总结一下我们之前使用中断的方式来进行数据的发送和接收 如果收到数据数据在RDR寄存器中 RXNE标志位就从0到1触发中断 进入中断服务函数 把数据缓存在队列中 然后在到进程函数中断接收数据函数中进行出队处理 发送数据就是把中断关闭&#xff08;标志位TXE…

日志模块Loguru

安装 Loguru 仅支持 Python 3.5 及以上的版本&#xff0c;使用 pip 安装即可&#xff1a; pip install loguru开箱即用 Loguru 的主要概念是只有一个&#xff1a;logger from loguru import loggerlogger.info("This is log info!") logger.warning("This i…

Python----网络爬虫

目录 1.Robots排除协议 2.request库的使用 3.beautifulsoup4库的使用 Python网络爬虫应用一般分为两部: &#xff08;1&#xff09;通过网络连接获取网页内容 &#xff08;2&#xff09;对获得的网页内容进行处理 - 这两个步骤分别使用不同的函数库&#xff1a;requests …

[Shell]获取Linux操作系统的发行版本

Linux命令uname -a输出分割成数组 # 将 uname -a 的输出分割成数组 IFS" " read -ra INFO <<< "$(uname -a)"# 打印数组中的各个元素 echo "System Name: ${INFO[0]}" echo "Node Name: ${INFO[1]}" echo "Kernel Vers…

食物相关的深度学习数据集合集—食物、饮料、肉类、餐具等数据集

最近收集了一大波与食物酒水相关的数据集&#xff0c;包含食物、饮料、肉类、餐具等不同等类型的数据集&#xff0c;废话不多说&#xff0c;给大家逐一介绍&#xff01;&#xff01; 1、自制啤酒配方数据库 超过20万自制啤酒配方数据库&#xff0c;数据集包含不同精酿啤酒的名…

危机公关之负面信息监测与处置原则

一家成功的企业不是没有人说它不好&#xff0c;而是企业通过公关或营销手段&#xff0c;让正面的声音碾压了负面的声音。小马识途建议企业创建之初就注意舆情公关的问题&#xff0c;不了解应该如何压制舆情负面信息的企业可以参考下面的几点建议。 1. 及时监测、观察、掌握和研…

C#有像Java ThreadLocal的类似实现吗?

在C#中&#xff0c;可以使用ThreadLocal<T>类来实现类似于Java中ThreadLocal的功能。ThreadLocal<T>类是.NET Framework提供的一个线程本地存储类&#xff0c;用于在每个线程中存储和访问特定于该线程的数据。 ThreadLocal<T>类允许每个线程都有自己独立的实…

Docker Image(镜像)——5

目录&#xff1a; Docker 镜像是什么镜像生活案例镜像分层生活案例为什么需要镜像镜像命令详解 镜像命令清单docker imagesdocker tagdocker pulldocker pushdocker rmidocker savedocker loaddocker historydocker importdocker image prunedocker build镜像操作案例 查找镜像…

etlbox.3.1.0 for NET 轻量级 ETL数据集成库 Crack

适用于 .NET 的轻量级 ETL&#xff08;提取、转换、加载&#xff09;工具箱和数据集成库 高度可定制 厌倦了使用几乎不可能实现复杂需求的用户界面&#xff1f;使用 ETLBox&#xff0c;可以轻松编写适合您独特需求的代码。插入您自己的逻辑或修改现有行为以满足您的特定要求。 …