【Godot4.2】SVGParser - SVG解析器函数库

概述

这是一个基于GDScript内置XMLParser编写的简易SVG文件解析函数库。

目的就是可以将SVG文件解析为GDSCript可以处理的字典或DOM形式,方便SVG渲染和编辑。

目前还只是一个简易实现版本。还需要一些改进。

函数库源码

# =============================================
# 名称:SVGParser
# 类型:静态函数库
# 描述:解析SVG文件,并转换为字典
# 作者:巽星石
# 创建时间:202472018:22:43
# 最后修改时间:202472101:17:52
# =============================================
class_name SVGParser# 标签顺序列表
# 返回SVG解析后的所有单标签和双标签的起始和结束标签
static func get_tags_list(path:String) -> Array:var tags:Array = []var xml = XMLParser.new()var err = xml.open(path)if err == OK:while xml.read() == OK:match xml.get_node_type():XMLParser.NODE_ELEMENT:  # 起始标签if xml.is_empty(): # 单标签(自闭合)tags.append("<%s />" % [xml.get_node_name()])else:tags.append("<%s>" %  [xml.get_node_name()])XMLParser.NODE_ELEMENT_END:  # 结束标签tags.append("</%s>" %  [xml.get_node_name()])	return tags# 将SVG文档转化为字典
static func to_dict(path:String) -> Dictionary:var xml = XMLParser.new()var err = xml.open(path)if err == OK:# 1.获取顺序标签列表(包含起始单标签、双标签的起始和结束标签)var tags:Array = []while xml.read() == OK:if xml.get_node_type() in [XMLParser.NODE_ELEMENT,XMLParser.NODE_ELEMENT_END]:# 构造字典var tag = {}if xml.get_node_type() == XMLParser.NODE_ELEMENT:tag["name"] = xml.get_node_name()else:tag["name"] = "/%s" % xml.get_node_name()tag["is_single"] = xml.is_empty()  # 是否单标签tag["index"] = tags.size()tag["children"] = []# 构造属性字典tag["attrs"] = {}for i in range(xml.get_attribute_count()):tag["attrs"][xml.get_attribute_name(i)] = xml.get_attribute_value(i)tags.append(tag)#print(JSON.stringify(tags,"\t"))# 2.使用栈获取双标签的其实和结束范围序列var stack:Array = []var arr:Array = []  # 双标签的起止索引for i in range(tags.size()):if tags[i]["is_single"] != true: # 双标签if !tags[i]["name"].begins_with("/"): #起始标签stack.push_front(tags[i])   # 推入else: # 结束标签var last_tag = stack.pop_front()if tags[i]["name"] == "/%s" % last_tag["name"]: # 起止标签匹配arr.append([last_tag["index"],tags[i]["index"]])#print(JSON.stringify(stack,"\t"))# 3.设定父子级别关系# 获取所有双标签的起始标签索引var dbl_indexs = []for i in range(arr.size()):dbl_indexs.append(arr[i][0])# 删除标签列表中所有双标签结束标签for i in range(tags.size()):if tags[i]["name"].begins_with("/"):tags[i] = nullfor tag in tags:if tag == null:tags.erase(tag)for tag in tags:if tag == null:tags.erase(tag)# 遍历双标签索引对,设定父子关系for i in range(arr.size()):var start = arr[i][0]var end = arr[i][1]# 遍历子标签for x in range(start+1,end):var tag = get_tag(tags,x)#print(tag)if tag != null and !tag["name"].begins_with("/"):get_tag(tags,start)["children"].append(tag)remove_tag(tags,x)return tags[0]else:return {}static func get_tag(tags,index):for tag in tags:if tag != null:if tag["index"] == index:return tagstatic func remove_tag(tags,index):for tag in tags:if tag != null:if tag["index"] == index:tags.erase(tag)# ================================== 简易DOM创建 ==================================
# SVG元素
class item:var tag_name:String = ""var attrs:Dictionaryvar children:Array[item] = [] # 子节点func _to_string() -> String:return "\n%s:%s\n" % [tag_name,str(children)]# 递归形式创建DOM
static func dom(item_dic:Dictionary) -> item:var itm = item.new()itm.tag_name = item_dic["name"]for dic in item_dic["children"]:itm.children.append(dom(dic))return itm# 返回SVG文件的DOM形式
static func to_DOM(path:String) -> item:var dict = to_dict(path)return dom(dict)

获取顺序标签列表

在这里插入图片描述

我们以Godot图标icon.svg为例,其SVG源码如下:

<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4" /><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z" /><path fill="#478cbf"d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" /><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z" /><circle cx="725" cy="526" r="90" /><circle cx="299" cy="526" r="90" /></g><g fill="#414042"><circle cx="307" cy="532" r="60" /><circle cx="717" cy="532" r="60" /></g></g>
</svg>

测试代码:

@tool
extends EditorScriptfunc _run() -> void:var tags = SVGParser.get_tags_list("icon.svg")print(JSON.stringify(tags,"\t"))

输出:

["<svg>","<rect />","<g>","<g>","<path />","<path />","<path />","<circle />","<circle />","</g>","<g>","<circle />","<circle />","</g>","</g>","</svg>"
]

可以看到其返回SVG解析后的所有单标签和双标签(包括起始和结束标签)的顺序列表。

通过它可以测试函数库是否正确解析了SVG文件的标签结构。

SVG转字典

  • to_dict()方法,可以将SVG文件内容解析和转化为GDScript的字典。

测试代码:

@tool
extends EditorScriptfunc _run() -> void:var dict = SVGParser.to_dict("res://icon.svg")print(JSON.stringify(dict,"\t"))

转化结果:

{"attrs": {"height": "128","width": "128","xmlns": "http://www.w3.org/2000/svg"},"children": [{"attrs": {"fill": "#363d52","height": "124","rx": "14","stroke": "#212532","stroke-width": "4","width": "124","x": "2","y": "2"},"children": [],"index": 1,"is_single": true,"name": "rect"},{"attrs": {"transform": "scale(.101) translate(122 122)"},"children": [{"attrs": {"fill": "#fff"},"children": [{"attrs": {"d": "M105 673v33q407 354 814 0v-33z"},"children": [],"index": 4,"is_single": true,"name": "path"},{"attrs": {"d": "m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z","fill": "#478cbf"},"children": [],"index": 5,"is_single": true,"name": "path"},{"attrs": {"d": "M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"},"children": [],"index": 6,"is_single": true,"name": "path"},{"attrs": {"cx": "725","cy": "526","r": "90"},"children": [],"index": 7,"is_single": true,"name": "circle"},{"attrs": {"cx": "299","cy": "526","r": "90"},"children": [],"index": 8,"is_single": true,"name": "circle"}],"index": 3,"is_single": false,"name": "g"},{"attrs": {"fill": "#414042"},"children": [{"attrs": {"cx": "307","cy": "532","r": "60"},"children": [],"index": 11,"is_single": true,"name": "circle"},{"attrs": {"cx": "717","cy": "532","r": "60"},"children": [],"index": 12,"is_single": true,"name": "circle"}],"index": 10,"is_single": false,"name": "g"}],"index": 2,"is_single": false,"name": "g"}],"index": 0,"is_single": false,"name": "svg"
}

目前除了text标签还需要一点特殊处理外,其他标签已经不存在明显解析问题。

在字典基础上,已经可以实现在Godot中的分层渲染和转为内置绘图函数绘制。也可以进一步转化为DOM形式,方便编辑和二次输出。

生成DOM

@tool
extends EditorScriptfunc _run() -> void:var dom = SVGParser.to_DOM("icon.svg")print(dom)

输出:

svg:[
rect:[]
, 
g:[
g:[
path:[]
, 
path:[]
, 
path:[]
, 
circle:[]
, 
circle:[]
]
, 
g:[
circle:[]
, 
circle:[]
]
]
]

整理后:

svg:[rect:[], g:[g:[path:[], path:[], path:[], circle:[], circle:[]], g:[circle:[], circle:[]]]
]

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

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

相关文章

【开源库学习】libodb库学习(三)

4 查询数据库 如果我们不知道我们正在寻找的对象的标识符&#xff0c;我们可以使用查询在数据库中搜索符合特定条件的对象。ODB查询功能是可选的&#xff0c;我们需要使用--generate-query ODB编译器选项显式请求生成必要的数据库支持代码。 ODB提供了一个灵活的查询API&#x…

【机器学习实战】Datawhale夏令营2:深度学习回顾

#DataWhale夏令营 #ai夏令营 文章目录 1. 深度学习的定义1.1 深度学习&#xff06;图神经网络1.2 机器学习和深度学习的关系 2. 深度学习的训练流程2.1 数学基础2.1.1 梯度下降法基本原理数学表达步骤学习率 α梯度下降的变体 2.1.2 神经网络与矩阵网络结构表示前向传播激活函数…

GESP CCF 图形化编程四级认证真题 2024年6月

一、单选题&#xff08;共 10 题&#xff0c;每题 2 分&#xff0c;共 30 分&#xff09; 题号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 答案 C B C D C D A B D C C D A A B 1、小…

整合Tess4J实现OCR图片识别技术

文章目录 1. 什么是OCR2. 什么是Tess4J库?3. 引入依赖4. 下载默认的训练数据5. 配置训练数据的目录路径6. 测试代码6.1 TesseractOcrConfig6.2 OcrController6.3 OcrService6.4 OcrServiceImpl 7. 功能测试7.1 调试请求接口7.2 测试结果 1. 什么是OCR **OCR &#xff08;Optic…

Spark的动态资源分配算法

文章目录 前言基于任务需求进行资源请求的整体过程资源申请的生成过程详解资源申请的生成过程的简单例子资源调度算法的代码解析 申请资源以后的处理&#xff1a;Executor的启动或者结束对于新启动的Container的处理对于结束的Container的处理 基于资源分配结果进行任务调度Pen…

AI算法22-决策树算法Decision Tree | DT

目录 决策树算法概述 决策树算法背景 决策树算法简介 决策树算法核心思想 决策树算法的工作过程 特征选择 信息增益 信息增益比 决策树的生成 ID3算法 C4.5的生成算法 决策树的修剪 算法步骤 决策树算法的代码实现 决策树算法的优缺点 优点 缺点 决策树算法的…

Unity游戏开发入门:从安装到创建你的第一个3D场景

目录 引言 一、Unity的安装 1. 访问Unity官网 2. 下载Unity Hub 3. 安装Unity Hub并安装Unity编辑器 二、创建你的第一个项目 1. 启动Unity Hub并创建新项目 2. 熟悉Unity编辑器界面 3. 添加基本对象 4. 调整对象属性 5. 添加光源 三、运行与预览 引言 Unity&…

html 单页面引用vue3和element-plus

引入方式&#xff1a; element-plus基于vue3.0&#xff0c;所以必须导入vue3.0的js文件&#xff0c;然后再导入element-plus自身所需的js以及css文件&#xff0c;导入文件有两种方法&#xff1a;外部引用、下载本地使用 通过外部引用ElementPlus的css和js文件 以及Vue3.0文件 …

冒泡,选择,插入,希尔排序

目录 一. 冒泡排序 1. 算法思想 2. 时间复杂度与空间复杂度 3. 代码实现 二. 选择排序 1. 算法思想 2. 时间复杂度与空间复杂度 3. 代码实现 三.插入排序 1. 直接插入排序 (1). 算法思想 (2). 时间复杂度与空间复杂度 (3). 代码实现 2. 希尔排序 (1). 算法思想 …

昇思25天学习打卡营第23天 | 基于MindSpore的红酒分类实验

学习心得&#xff1a;基于MindSpore的红酒分类实验 在机器学习的学习路径中&#xff0c;理解和实践经典算法是非常重要的一步。最近我进行了一个有趣的实验&#xff0c;使用MindSpore框架实现了K近邻&#xff08;KNN&#xff09;算法进行红酒分类。这个实验不仅加深了我对KNN算…

云手机结合自主ADB命令接口 提升海外营销效率

现在&#xff0c;跨境电商直播已经成为在线零售的重要渠道&#xff0c;在大环境下&#xff0c;确保直播应用的稳定性和用户体验至关重要。 云手机支持自主ADB命令接口&#xff0c;为电商直播营销提供了技术支持&#xff0c;使得应用开发、测试、优化和运维更加高效。 什么是A…

卷积神经网络学习问题总结

问题一&#xff1a; 深度学习中的损失函数和应用场景 回归任务&#xff1a; 均方误差函数&#xff08;MSE&#xff09;适用于回归任务&#xff0c;如预测房价、预测股票价格等。 import torch.nn as nn loss_fn nn.MSELoss() 分类任务&#xff1a; 交叉熵损失函数&…

用go实现限流算法

文章目录 固定窗口优缺点&#xff1a;适用场景&#xff1a;总结&#xff1a; 滑动窗口优缺点&#xff1a;适用场景&#xff1a;总结&#xff1a; 漏桶限流器优缺点&#xff1a;适用场景&#xff1a;总结&#xff1a; 令牌桶优缺点&#xff1a;适用场景&#xff1a;总结&#xf…

SpringBoot结合ip2region实现博客评论显示IP属地

你好呀&#xff0c;我是小邹。 在现代的Web应用中&#xff0c;特别是博客和论坛类网站&#xff0c;为用户提供地理定位服务&#xff08;如显示用户所在地理位置&#xff09;可以极大地增强用户体验。本文将详细探讨如何使用Java和相关技术栈来实现在博客评论中显示用户的地址信…

NXP i.MX8系列平台开发讲解 - 3.19 Linux TTY子系统(二)

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 目录 1. Linux 串口驱动 1.1 Uart 驱动注册流程 1.2 uart 操作函数 1.3 line discipline 2. Linux tty应用层使用…

【 DHT11 温湿度传感器】使用STC89C51读取发送到串口、通过时序图编写C语言

文章目录 DHT11 温湿度传感器概述接线数据传送通讯过程时序图检测模块是否存在 代码实现总结对tmp tmp << 1;的理解对sendByte(datas[0]/10 0x30);的理解 DHT11 温湿度传感器 使用80C51单片机通过读取HDT11温湿度传感的数据&#xff0c;发送到串口。 通过时序图编写相应…

2024-07-18 Unity插件 Odin Inspector8 —— Type Specific Attributes

文章目录 1 说明2 特定类型特性2.1 AssetList2.2 AssetSelector2.3 ChildGameObjectsOnly2.4 ColorPalette2.5 DisplayAsString2.6 EnumPaging2.7 EnumToggleButtons2.8 FilePath2.9 FolderPath2.10 HideInInlineEditors2.11 HideInTables2.12 HideMonoScript2.13 HideReferenc…

STM32学习(3)--GPIO输入

GPIO输入 3.1GPIO输入1.按键介绍2.传感器模块介绍3.硬件电路4.C语言知识点补充&#xff08;1&#xff09;C语言数据类型&#xff08;2&#xff09;C语言宏定义&#xff08;3&#xff09;C语言typedef(4)C语言结构体&#xff08;5&#xff09;C语言枚举 3.2按键控制LED代码1.mai…

Python爬虫(基本流程)

1. 确定目标和范围 明确需求&#xff1a;确定你需要从哪些网站抓取哪些数据。合法性&#xff1a;检查目标网站的robots.txt文件&#xff0c;了解哪些内容可以被抓取。数据范围&#xff1a;确定爬取数据的起始和结束点&#xff0c;比如时间范围、页面数量等。 2. 选择合适的工…

深入理解Linux网络(二):UDP接收内核探究

深入理解Linux网络&#xff08;二&#xff09;&#xff1a;UDP接收内核探究 一、UDP 协议处理二、recvfrom 系统调⽤实现 一、UDP 协议处理 udp 协议的处理函数是 udp_rcv。 //file: net/ipv4/udp.c int udp_rcv(struct sk_buff *skb) {return __udp4_lib_rcv(skb, &udp_…