如果说 SkCanvas 是画布,是所有绘图操作的提供者的话,那么 SkSurface 就是画布的容器,我们称之为表面,它负责管理画布对应的像素数据。这些像素数据可以是在内存中创建的,也可以是在 GPU 显存中创建的。

创建一个空白表面

如何创建和使用 Skia 的 SkSurface 对象,如下代码所示:

SkImageInfo imgInfo = SkImageInfo::MakeN32Premul(800, 600);
sk_sp<SkSurface> surface = SkSurfaces::Raster(imgInfo);

SkSurfaces::Raster 方法执行后,应用程序将在内存中分配指定数量的像素。

若需要使用 SkSurface 对象管理的像素,可以通过如下方法来完成工作:

SkPixmap pixmap;
surface->peekPixels(&pixmap);
auto addr = pixmap.addr();

pixmap.addr() 用于获取像素数据的内存地址,一般情况下,开发者不会使用这个地址来改变具体的某个像素的值。

因为内存中存储的像素数据是被格式化过的,并不是A,R,G,B颜色分量依次排列的数值。像素数据在内存中的排布方式与 SkSurface 的颜色空间有关。

通过如下代码,你可以获取某个具体位置的颜色:

SkColor color = pixmap.getColor(0, 0);  //画布上位置 0,0 的颜色

根据现有像素数据创建表面

如果你已经拥有了像素数据,就可以直接基于你的像素数据创建 SkSurface 对象,如下代码所示:

std::vector<SkColor> surfaceMemory;
surfaceMemory.resize(w * h);
SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
sk_sp<SkSurface> surface = SkSurfaces::WrapPixels(info, &surfaceMemory.front(), w * sizeof(SkColor));

上面代码中使用 std::vector<SkColor> 来存储像素数据。

每个像素就是一个 SkColor 类型的数据(SkColor就是 uint32_t )。

像素容器的大小是 w * h,(二维数组的列数 w 和行数 h ,与窗口的宽和高相同)

SkSurfaces::WrapPixels 方法基于像素数据创建 SkSurface 对象。

其中 &surfaceMemory.front() 用于获取容器内第一个像素的地址,

w * sizeof(SkColor) 是每行数据的大小。

同样道理,如果你有一个 SkBitmap 对象,就可以根据这个对象的像素数据创建表面:

SkBitmap bitmap;
bitmap.allocN32Pixels(w, h);
sk_sp<SkSurface> surface = SkSurfaces::WrapPixels(bitmap.pixmap());

上述代码使用 SkBitmap 对象的 allocN32Pixels 方法为此对象创建了指定大小的内存空间用于存储像素数据。

SkBitmap 对象的 pixmap 方法负责获取 SkBitmap 对象的像素数据的内存地址。

重置表面像素数据

如果你想批量把一个表面的像素数据全部设置为某个颜色值。

就可以用以下两个办法达到这个目的:

auto canvas = surface->getCanvas();
canvas->clear(0x66778899);  //方法1
canvas->drawColor(0x22FF8899); //方法2
SkPaint paintObj;
canvas->drawPaint(paintObj); //方法3

这都是通过画布对象 SkCanvas 完成的。

也可以在源头设置所有像素的值,如下代码所示

std::vector<SkColor> surfaceMemory(w * h, 0xffff00); //初始化像素数组时,即设置好像素颜色surfaceMemory.resize(w * h,0xffff00); //更改像素容器大小时,重置整个容器的像素颜色

覆盖表面像素数据

如果你已经有了一组像素数据,需要把这些像素写入目标表面,可以通过如下方法完成:

void surfaceWritePixels(SkSurface *surface)
{std::vector<SkColor> srcMem(200 * 200, 0xff00ffff);SkBitmap dstBitmap;dstBitmap.setInfo(SkImageInfo::MakeN32Premul(200, 200));dstBitmap.setPixels(&srcMem.front());surface->writePixels(dstBitmap, 100, 100);
}

在这段代码中,使用 SkBitmap 类型包装了像素数据。

SkBitmap 对象的 setPixels 方法会把 srcMem 管理的像素地址拷贝到 SkBitmap 对象中(只复制了地址)

SkSurface 对象的 writePixels 方法会把 dstBitmap 对象管理的像素数据复制到自己管理的内存数据中。

复制是从 100,100 的位置开始的,由于 dstBitmap 只管理了 200×200 的像素数据,所以复制工作执行到坐标 300,300 就结束了。

程序运行的结果如下图所示:

覆盖表面像素.png

表面与画布的互访

通过 SkSurface 对象的 getCanvas 方法得到一个与此表面有关的画布。

也可以通过 SkCanvas 对象的 getSurface 方法得到一个与此画布有关的表面。

但需要注意的是,SkCanvas 对象的 getSurface 方法并不是总能得到与之对应的 SkSurface 对象。

比如:

auto canvas = SkCanvas::MakeRasterDirect(info, &surfaceMemory.front(), 4 * w);
auto surface = canvas->getSurface();

这个 canvas 对象是手动创建的,它不依赖任何surface,它的 getSurface 方法的返回值就是一个空指针。

虽然这个 canvas 没有与之对应的 surface,可以通过如下方法创建一个:

SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
auto surface = canvas->makeSurface(info);

需要注意的是,这样做会导致 canvas 对应的像素数据被复制到 surface 内(内存占用加倍)

所以要么先创建surface再通过surface得到canvas,要么仅使用canvas,不使用surface

尽量不要通过canvas去创建surface

当一个应用中存在多个surface的时候,往往需要合并这些surface

有很多办法可以完成这项任务,其中之一就是把一个 surface 绘制到另一个 canvas 中,如下代码所示:

surface->draw(canvas.get(), 0, 0);

这行代码会把 surface 管理的像素数据,绘制到 canvas 画布上(从坐标 0,0 位置开始绘制),这就达到了合并两个 surface 的效果。

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

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

相关文章

26.(vue3.x+vite)以pinia为中心的开发模板

效果截图 代码实现 HelloWorld.vue <template><div style="padding: 20px;">介绍:<br>1:使用class 来减少pinia(store)的代码量<br>

华为AI Agent智能园艺助手开发案例

一、引言与行业背景 在数字化与智能化日益渗透我们生活的今天&#xff0c;园艺这一传统而充满生机的领域&#xff0c;也迎来了智能化的革新。华为AI Agent智能园艺助手通过融合人工智能与园艺专业知识&#xff0c;为用户提供一站式、个性化的园艺养护解决方案&#xff0c;彻底改…

Linux Flathub软件管理方法 使用指南

Flathub 使用指南&#xff1a;软件安装、管理及常用软件推荐 一. 什么是 Flathub&#xff1f; Flathub 是 Flatpak 应用程序的主要分发中心&#xff0c;类似于 Linux 上的"应用商店"。它提供了一种跨发行版的软件打包和分发方式&#xff0c;让用户可以在任何 Linux 发…

GitLab 18.2 发布几十项与 DevSecOps 有关的功能,可升级体验【二】

沿袭我们的月度发布传统&#xff0c;极狐GitLab 发布了 18.2 版本&#xff0c;该版本带来了议题和任务的自定义工作流状态、新的合并请求主页、新的群组概览合规仪表盘、下载安全报告的 PDF 导出文件、中心化的安全策略管理&#xff08;Beta&#xff09;等几十个重点功能的改进…

​​免费语音转换服务(TTS)全面指南

​​​​1. TTS技术概述​​ TTS&#xff08;Text-to-Speech&#xff09;通过AI将文字转化为自然语音&#xff0c;核心技术包括​​深度神经网络&#xff08;DNN&#xff09;​​、​​语音韵律建模​​和​​声学合成​​。其核心优势在于&#xff1a; ​​多语言支持​​&a…

正则化都是放在模型的哪个位置呢?

✅ 什么是“正则化”&#xff1f;在神经网络中&#xff0c;正则化&#xff08;Regularization&#xff09; 抑制过拟合的技巧 目的是让模型在训练集和测试集上都表现得好&#xff08;泛化能力强&#xff09;。&#x1f9e0; 常见的正则化手段包括&#xff1a;方法类型通常放在哪…

Python毕业设计 | 基于协同过滤的智能商品推荐与数据大屏系统(Vue+Flask+Scikit-learn,附源码+文档)

个人介绍&#x1f3af; 毕业设计私人教练 专注计算机毕设辅导第 6 年&#xff0c;累计 1v1 带飞 800 同学顺利通关。从选题、开题、代码、论文到答辩&#xff0c;一条龙陪跑&#xff1b;擅长把导师的 “模糊要求” 变成能落地的技术方案。白天写方案&#xff0c;晚上改论文&…

基于千问2.5-VL-7B训练识别人的表情

一、安装LLaMA-Factory 我们使用LLaMA-Factory来进行微调&#xff0c;安装LLaMA-Factory来参考文章&#xff1a; 大模型微调工具LLaMA-Factory的安装流程-CSDN博客 二、下载千问2.5-VL-7B模型 我们使用千问2.5-VL-7B多模态模型来进行微调 通义千问2.5-VL-7B-Instruct 下载…

Android屏幕适配:从dp到px的转换与今日头条适配方案详解

前言 在Android开发中&#xff0c;屏幕适配一直是一个重要且复杂的话题。不同设备有着不同的屏幕尺寸、分辨率和像素密度&#xff0c;如何让应用在各种设备上都能良好显示&#xff0c;是每个开发者都需要面对的问题。本文将深入探讨Android系统中dp到px的转换原理&#xff0c;并…

nvim 缩进4空格

要把 Neovim 配置为缩进 4 空格&#xff0c;并适用于所有语言&#xff08;或某些语言如 C/C&#xff09;&#xff0c;你只需要设置这三个核心选项即可&#xff1a;✅ 通用方式&#xff1a;在 init.lua 或 options.lua 中添加 vim.opt.tabstop 4 -- 一个 <Tab> 等…

pdw估计edw怎么估计

问题一、pdw估计edw怎么估计PDW&#xff08;Pulse Descriptor Word&#xff09;数据是雷达接收到的每一个脉冲的瞬时特征数据&#xff0c;EDW&#xff08;Emitter Descriptor Word&#xff09;是对某一辐射源&#xff08;发射机&#xff09;整体特性的估计。PDW 是每一个脉冲的…

TS语法最佳实践

switch 的 case不能使用条件表达式JavaScript 允许在 switch 的 case 中使用条件表达式&#xff0c;但这种用法实际上是无效的&#xff0c;因为 case 的值会被隐式地转换为布尔值。TypeScript 明确禁止这种用法&#xff0c;以避免隐式类型转换导致的逻辑错误。建议使用 if-else…

行业热点丨仿真历史数据难以使用?如何利用几何深度学习破局,加速汽车工程创新

01、AI 驱动研发升级&#xff1a;几何深度学习创造行业新价值人工智能正加速推动各行业研发能力升级。麦肯锡最新报告显示&#xff0c;该技术在制药、化工和航空航天等领域的应用&#xff0c;有望为相关企业创造高达5600亿美元的经济价值。 AI 技术应用的先行者&#xff0c;全球…

JSBridge原理与实现全解析

JSBridge 是用于连接 JavaScript&#xff08;H5&#xff09; 和原生应用&#xff08;iOS/Android&#xff09;的桥梁&#xff0c;允许它们之间相互调用方法。 &#x1f309; 一、JSBridge 双向通信流程图 #mermaid-svg-AoDVdJL2VJBnTJ2Q {font-family:"trebuchet ms"…

Mockito:Java单元测试Mock框架

文章目录一、写在前面1、简介2、依赖二、使用1、基本使用2、注解&#xff08;1&#xff09;开启注解&#xff08;2&#xff09;Mock 注解&#xff08;3&#xff09;DoNotMock 注解&#xff08;4&#xff09;Spy 注解&#xff08;5&#xff09;Captor 注解&#xff08;6&#xf…

群晖Synology Drive:打造高效安全的私有云协作平台

随着企业与个人对数据协作、安全与自主性的需求不断提升&#xff0c;群晖&#xff08;Synology&#xff09;推出的 Synology Drive 成为了私人云存储与团队协作的利器。下面将从功能亮点、使用方式、安全管理、适用场景等角度&#xff0c;为你全面解读这款强大的私有云方案。Sy…

开发避坑短篇(11):Oracle DATE(7)到MySQL时间类型精度冲突解决方案

异常信息 [Err] [Dtf] 1426 - Too-big precision 7 specified for CREATE_TIME. Maximum is 6.异常背景 用Navicat的数据传输功能进行oracle的数据表迁移到到mysql时报错。 异常分析 oracle的DATE类型的长度是7位&#xff0c;而mysql的datetime类型的长度最多6位&#xff0c;所…

怎么判断一个DAPP是否真正去中心化

判断一个DAPP&#xff08;去中心化应用&#xff09;是否真正去中心化&#xff0c;需要从多个维度进行考察。以下是关键评估标准&#xff1a;1. 区块链依赖程度✅ 真正去中心化&#xff1a;核心逻辑和数据处理完全依赖智能合约&#xff0c;运行在区块链上&#xff08;如以太坊、…

F12 开发者工具 使用指北

F12 开发者工具 使用指北元素 Elements控制台 Console源代码 Sources网络 Network请求文件具体说明首先介绍Chrome开发者工具中&#xff0c;调试时使用最多的三个功能页面是&#xff1a;元素&#xff08;ELements&#xff09;、控制台&#xff08;Console&#xff09;、源代码&…

AD域设计与管理-域策略-进阶

AD域安全保密要求&#xff0c;也是最为常见的一些组策略配置需求 目录 1.禁止U盘&#xff0c;DVD&#xff0c;软盘等可移动存储使用 2.禁止员工自行安装软件 3.硬盘全部采用bitlocker上锁&#xff0c;密码保存至AD域控 4.密码复杂度要求 5.开启windows防火墙且不允许员工…