news 2026/10/22 0:41:33

RGF 仓颉版位图画刷实战指南:从位图与图层创建到平铺填充渲染

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RGF 仓颉版位图画刷实战指南:从位图与图层创建到平铺填充渲染
  • 图形学
  • 桌面应用

【免费下载链接】RGF_CJ

RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。

项目地址:https://gitcode.com/Cangjie-SIG/RGF_CJ
点击查看免费下载

位图画刷(BitmapBrush)是 RGF 渲染框架中一种以图片内容作为填充源的设备相关资源,在掌握位图加载与图层绘制之后,即可基于二者创建位图画刷,进而实现图片的重复平铺、区域填充等批量渲染效果。本文将以 RGF_CJ 官方教程第十一课为骨架,结合仓库源码与测试用例,完整讲解位图画刷的成员声明、两种创建方式、底层分发原理、填充绘制与资源释放,帮助你在仓颉 Windows 应用开发中直接落地使用。

位图画刷概述

在 RGF_CJ 中,画刷是绘制图形时必不可少的“颜料源”。与纯色画刷用单一颜色填充不同,位图画刷将一张位图或一个图层的内容作为填充源,绘制时可以把图片“刷”到矩形、椭圆、圆角矩形等目标区域中,并支持基于图片内容的重复平铺。

位图画刷在源码中定义于 src/rgf_core/rgf_brush_bitmap.cj,其类型层级如下:

public open class BitmapBrush <: Brush{ public init(){ super(CPointer<Unit>()) } internal init(oPtr:CPointer<Unit>){ super(oPtr) } ... }
  • BitmapBrush继承自画刷父类Brush(定义于 src/rgf_core/rgf_brush.cj),因此天然具备Brush提供的线宽读取与设置能力(getLineWidth()/setLineWidth())。
  • 从注释可知,位图画刷属于设备相关资源,即其生命周期与底层图形设备(窗口渲染表面surface)绑定,需要遵循 RGF 的资源创建与释放约定。

创建位图画刷

第一步:声明画刷成员

与位图、图层等设备相关资源一样,位图画刷需要先作为窗口类的成员存在。使用@LifeCycle宏后,框架会自动接管类成员资源的管理(自动构造与自动释放),无需再手动初始化:

@LifeCycle class WinSelf <: WinCore{ let bmpBrh:BitmapBrush }

补充说明:@LifeCycle宏只接管类成员的自动化管理;对于函数内部临时创建的设备相关资源,仍需在结束后手动调用release()释放(详见下文“资源释放”小节,该约定同样适用于位图画刷)。

方式一:从位图创建位图画刷

位图画刷最常见的来源是一张已加载的位图。先通过渲染表面surface的createBitmap()从本地图片文件创建位图,再基于该位图对象创建画刷:

public override func createDeviceResources():Bool{ // 从文件创建位图对象 let bmp:Bitmap = surface.createBitmap("./res/test.png") // 基于位图对象创建位图画刷 surface.createBitmapBrush(bmpBrh,bmp) // 释放临时的位图对象 bmp.release() return true; }

要点说明:

  • 路径支持相对路径,示例中的"./res/test.png"对应仓库 res/test.png;RGF_CJ目前支持JPEG、PNG等常用图片格式(参见第七课《加载并渲染图片》)。
  • 从文件创建位图时,底层实现会将字符串路径转换为宽字符串并调用rApiDctClassCreateBitmapFromFile(见 src/rgf_core/rgf_renderer.cj)。
  • 位图对象只是创建画刷的临时载体,画刷创建完成后即调用bmp.release()释放,避免设备相关资源泄漏。

方式二:从图层创建位图画刷

如果你需要以一段“绘制好的内容”作为填充源(例如预先在图层里画好的图案),可以先把内容绘制进一个图层,再把整个图层交给位图画刷:

public override func createDeviceResources():Bool{ // 创建一个 10*10 的图层 let lay:Layer = surface.createLayer(10,10) lay.draw{=> // 在图层中绘制些什么 } // 基于图层对象创建位图画刷 surface.createBitmapBrush(bmpBrh,lay) // 释放临时的图层对象 lay.release() return true; }

要点说明:

  • 图层通过surface.createLayer(width, height)创建,该接口定义于 src/rgf_core/rgf_draw_creater.cj。
  • Layer类型(src/rgf_core/rgf_layer.cj)同时实现了Image与IDraw接口,因此图层既可作为图像源(Image),也可像渲染表面一样承载绘制操作(IDraw,支持drawLine、drawRectangle、drawBitmap等方法)。
  • 图层内的一切绘制都应包裹在lay.draw{=> ... }中执行(唯一的例外是onPaint()中surface、bindSurface可直接绘制而无需嵌套draw()),这一约定在第十课《更多的图层》中有明确说明。
  • 同样地,图层对象用完即释放。

底层原理:按图像类型自动分发

为什么createBitmapBrush既能接收位图又能接收图层?从接口定义(src/rgf_core/rgf_draw_creater.cj)可以看到,createBitmapBrush的参数类型统一为Image——而Bitmap与Layer都继承自Image。在 src/rgf_core/rgf_renderer.cj 的实现中,框架会根据实际传入对象的子类型(SfcSubObjType.Bitmap或SfcSubObjType.Layer)分别调用底层对应的原生创建接口:

public func createBitmapBrush (img:Image):BitmapBrush{ if(!isValid() || !img.isValid()){ throw Exception(rgfErrorCpluapluaObjNotExist) } if(img.objType == SfcSubObjType.Bitmap){ return BitmapBrush(unsafe{ rApiDctClassCreateBitmapBrush(objPtr,img.objPtr) }) }else if(img.objType == SfcSubObjType.Layer){ return BitmapBrush(unsafe{ rApiDctClassCreateBitmapBrushLay(objPtr,img.objPtr) }) } throw Exception(rgfErrorCpluapluaObjNotExist) }

由此可以推断:位图画刷的“内容源”本质上就是一张图像(位图或图层),这也是它能实现“基于图片内容重复平铺”的根源。另外注意,若传入的Image既不是位图也不是图层,或底层对象尚未创建,接口会抛出rgfErrorCpluapluaObjNotExist异常。

使用位图画刷

创建好的画刷要在绘制方法中发挥价值。surface渲染表面提供了大量以fill和draw开头的绘制方法——前者表示填充、后者表示描边(该语义约定见第五课《使用纯色画刷》),这些方法通常都需要一个画刷参数。以绘制矩形为例:

public override func onPaint(wRect:Rect):Unit{ surface.clear(1.0,1.0,1.0,1.0) // 获取渲染表面矩形 var rect:Rect = surface.getRect() rect = Rect( rect.left + 10, rect.top + 10, rect.right - 10, rect.bottom - 10 ) // 绘制矩形 surface.fillRectangle(rect,bmpBrh) }

代码解读:

  • surface.clear(1.0, 1.0, 1.0, 1.0)将窗口清为不透明白色;
  • surface.getRect()获取渲染表面(窗口客户区)的矩形范围;
  • 随后构造一个四周各缩进 10 单位的矩形,使填充区域与窗口边缘保留 10 单位的留白;
  • surface.fillRectangle(rect, bmpBrh)用位图画刷填充该矩形区域,填充内容即画刷所承载的图片/图层。

fillRectangle在 src/rgf_core/rgf_renderer.cj 中提供了(x, y, width, height)、FRect、Rect三种重载形式,最终统一调用底层rApiDttClassFillRectangle完成填充。同理,fillEllipse、fillRoundedRectangle等填充方法也都可以搭配位图画刷使用,以填充圆形、圆角矩形等目标区域。

调试运行程序,即可看到位图画刷填充的效果:

资源释放与生命周期管理

位图画刷属于设备相关资源,其释放遵循 RGF 的统一约定:

  • 类成员:搭配@LifeCycle宏使用时,框架自动接管创建与释放,无需(也不要)在destroyDeviceResources()中手动调用release();
  • 函数内临时对象:如在createDeviceResources()中临时创建的位图、图层等载体对象,用完后应立即release()(如前述示例中的bmp.release()/lay.release())。

从底层实现看,release()定义于 src/rgf_core/rgf_base.cj,它调用原生释放接口后将内部指针置空,使对象失效;重复调用是安全的。若在对象已释放后继续调用涉及底层对象的方法,会抛出“对象不存在”异常。

测试用例中的真实用法

在仓库的集成测试 test/HLT/base/src/test_win.cj 中,可以看到位图画刷与图层组合使用的完整场景——先创建图层,再从文件加载位图、创建位图画刷,最后在图层中绘制:

layer = surface.createLayer(210, 210); let img:Bitmap = surface.createBitmap("./res/test.png"); imgBrush = surface.createBitmapBrush(img); // 可以使用尾随lambda绘制 layer.draw(){=> layer.drawPath(path,slbbrush) layer.drawBitmap(0.0, 0.0, 210.0, 210.0, img, 0.0, 0.0, 210.0, 210.0,alpha:0.5) } surface.resetLayerSize(layer,200,200)

这段代码印证了两个实战要点:

  1. createBitmapBrush(img)可以直接接收createBitmap(uri)的返回值(返回值式创建);
  2. 位图画刷与图层、路径、位图渲染等能力可以自由组合,绘制逻辑统一收敛在draw()中。

小结

本文围绕 RGF_CJ 位图画刷的完整使用链路展开:BitmapBrush继承自Brush,属于设备相关资源;创建时既可以从文件位图(createBitmap→createBitmapBrush)而来,也可以从图层(createLayer→ 图层内绘制 →createBitmapBrush)而来,底层会按Bitmap/Layer子类型自动分发到对应的原生创建接口;使用时配合fillRectangle等填充方法即可实现基于图片内容的区域填充与平铺渲染。掌握位图画刷后,你便可以在 RGF 应用中用图片素材驱动图形界面的批量填充效果,为后续学习渐变画刷、文本渲染与矩阵变换打下坚实基础。

  • 图形学
  • 桌面应用

【免费下载链接】RGF_CJ

RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。

项目地址:https://gitcode.com/Cangjie-SIG/RGF_CJ
点击查看免费下载
上一篇:挑战无损音乐获取难题:NeteaseCloudMusicFlac实现FLAC格式批量下载革命
下一篇:DefectDojo配置最佳实践:从单机到生产环境的实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 10:56:52

Prim算法详解:从手算到代码实现最小生成树

1. 从一张网线布线图说起&#xff1a;Prim算法到底在解决什么问题很多刚接触图论的朋友第一次听到“最小生成树”这个词&#xff0c;脑子里冒出来的问号比代码行数还多。我当初也一样&#xff0c;直到有一次帮朋友规划一个小型办公区的网线走线——六个工位&#xff0c;两两之间…

作者头像 李华
网站建设 2026/10/20 19:40:15

Django与Flask整合开发公务员考试系统实践

1. 项目概述与核心价值这个公务员考试练习系统项目采用了前后端分离的架构设计&#xff0c;后端同时整合了Django和Flask两大Python框架&#xff0c;前端使用Vue.js实现动态交互界面&#xff0c;开发环境选择了PyCharm这款专业的Python IDE。这种技术组合在当前教育类Web应用中…

作者头像 李华
网站建设 2026/10/19 9:43:33

Matlab实现氢能综合能源系统优化调度模型

1. 项目背景与核心价值氢能作为清洁能源的重要载体&#xff0c;正在重塑综合能源系统的运行方式。这项研究通过Matlab实现了计及氢能的综合能源系统优化调度模型&#xff0c;为多能互补系统提供了量化分析工具。我在参与某工业园区微电网项目时&#xff0c;深刻体会到传统能源调…

作者头像 李华
网站建设 2026/10/19 15:14:46

PoE Build 规划器:离线算伤害,快速规划角色

PoE Build 规划器&#xff1a;离线算伤害&#xff0c;快速规划角色 【免费下载链接】PathOfBuilding Offline build planner for Path of Exile. 项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuilding 还在为天赋加点和装备搭配反复纠结&#xff0c;算不清…

作者头像 李华