【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.mzph.cn/bicheng/48435.shtml

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

相关文章

AI算法23-决策树ID3算法Iterative Dichotomiser 3 | ID3

目录 决策树ID3算法概述 决策树ID3算法简介 决策树ID3算法的原理 决策树ID3算法的核心 决策树ID3算法的本质 决策树ID3算法的基本流程 决策树ID3算法计算过程 步骤1 步骤2 步骤3 决策树ID3算法的代码实现 决策树ID3算法的优缺点 优点 缺点 决策树ID3算法的应用场…

ue5笔记

1 点光源 聚光源 矩形光源 参数比较好理解 &#xff08;窗口里面&#xff09;环境光混合器&#xff1a;快速创造关于环境光的组件 大气光源&#xff1a;太阳光&#xff0c;定向光源 天空大气&#xff1a;蓝色的天空和大气 高度雾&#xff1a;大气下面的高度感的雾气 体积…

【HarmonyOS】HarmonyOS NEXT学习日记:五、交互与状态管理

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;五、交互与状态管理 在之前我们已经学习了页面布局相关的知识&#xff0c;绘制静态页面已经问题不大。那么今天来学习一下如何让页面动起来、并且结合所学完成一个代码实例。 交互 如果是为移动端开发应用&#xff0c;那么交…

自主巡航,目标射击

中国机器人及人工智能大赛 参赛经验&#xff1a; 自主巡航赛道 【机器人和人工智能——自主巡航赛项】动手实践篇-CSDN博客 主要逻辑代码 #!/usr/bin/env python #coding: utf-8import rospy from geometry_msgs.msg import Point import threading import actionlib impor…

鸿蒙开发 03 封装 @ohos/axios (最新深度封装)

鸿蒙开发 03 封装 ohos/axios &#xff08;最新深度封装&#xff09; 1、安装 ohos/axios2、开始封装2.1 新建 utils 文件夹 和 api 文件夹2.2 在 utils 文件夹里新建 http.ts2.3 在 api 文件夹里新建 api.ets 3、页面调用4、打印结果 1、安装 ohos/axios ohpm install ohos/a…

linux环境交叉编译openssl库,以使Qt支持https

一.前言 Qt若需要支持https&#xff0c;则需要openssl的支撑,并且要注意&#xff0c;Qt不同版本会指定对应的openssl版本库&#xff0c;比方我用的Qt5.15.10他要求用的openssl版本是1.1.1&#xff0c;你就不能用其他版本&#xff0c;不然基本就是失败报错。 如何查看Qt对应ope…

无人机反制技术常见的有哪些?

随着无人机技术的迅速发展和广泛应用&#xff0c;无人机在民用、军事等领域都发挥着重要作用。然而&#xff0c;无人机的滥用和非法入侵也带来了严重的安全隐患。为了维护国家安全和社会稳定&#xff0c;无人机反制技术应运而生。本文将详细介绍无人机反制技术的常见类型&#…

【Git学习 | 第2篇】在IDEA中使用Git

文章目录 在IDEA中使用Git1. IDEA中配置Git2. 获取Git仓库2.1 本地初始化仓库2.2 从远程仓库克隆 3. 本地仓库操作4. 远程仓库操作5. 分支操作 在IDEA中使用Git 1. IDEA中配置Git IDEA中使用Git&#xff0c;本质上使用的本地安装的Git软件配置步骤&#xff1a; 2. 获取Git仓库…

Unity UGUI 之 RectTransform

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 Unity - Manual: Rect Transform 1.Rect Transform是什么 2.轴心与锚点的映射关系 首先…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【29】Sentinel

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【29】Sentinel 简介熔断降级什么是熔断什么是降级相同点不同点 整合Sentinel自定义sentinel流控返回数据使用Sentinel来保护feign远程调用自定义资源给网关整合Sentinel参考 简介 熔断降…

阿里开源的音频模型_原理与实操

英文名称: FunAudioLLM: Voice Understanding and Generation Foundation Models for Natural Interaction Between Humans and LLMs 中文名称: FunAudioLLM: 人与LLMs之间自然互动的语音理解和生成基础模型 论文地址: http://arxiv.org/abs/2407.04051v3 相关论文&#xff1a;…

人话讲下如何用github actions编译flutter应用-以编译windows为例

actions的脚本看下这个&#xff0c;有简单的说明&#xff0c;有关于编译个平台的脚本&#xff1a; https://github.com/marketplace/actions/flutter-action 打开你要编译的项目点击那个Actions按钮 然后随便点击一个脚本会跳到白框编辑界面 打开上文提到的网址随便抄下就ok …

达梦数据库(一)mysql2dm

达梦数据库(一)mysql2dm 文章目录 达梦数据库(一)mysql2dm一、安装篇ForWindows二、数据库初始化篇三、数据迁移篇出现的问题找不到对应表或者视图 注意字符集模式迁移出错大小写敏感解决方案 四、 代码修改篇group_concatGROUP BY方法一方法二(最笨)方法补充 多表联查更新参考…

1.17、基于竞争层的竞争学习(matlab)

1、基于竞争层的竞争学习简介及原理 竞争学习是一种无监督学习方法&#xff0c;其中的竞争层神经元之间互相竞争以学习输入模式的表示。竞争学习的一个经典模型是竞争神经网络&#xff08;Competitive Neural Network&#xff0c;简称CNN&#xff09;&#xff0c;其核心部分是…

Linux复习02

一、什么是操作系统 操作系统是一款做软硬件管理的软件&#xff01; 一个好的操作系统&#xff0c;衡量的指标是&#xff1a;稳定、快、安全 操作系统的核心工作&#xff1a; 通过对下管理好软硬件资源的手段&#xff0c;达到对上提供良好的&#xff08;稳定&#xff0c;快…

什么是单例模式,有哪些应用?

目录 一、定义 二、应用场景 三、6种实现方式 1、懒汉式&#xff0c;线程不安全。 2、懒汉式&#xff0c;线程安全 3、双检锁/双重校验锁&#xff08;DCL&#xff0c;即 double-checked locking&#xff09; 4、静态内部类方式-------只适用于静态域 5、饿汉式 6、枚举…

嵌入式C++、STM32、树莓派4B、OpenCV、TensorFlow/Keras深度学习:基于边缘计算的实时异常行为识别

1. 项目概述 随着物联网和人工智能技术的发展,智能家居安全系统越来越受到人们的关注。本项目旨在设计并实现一套基于边缘计算的智能家居安全系统,利用STM32微控制器和树莓派等边缘设备,实时分析摄像头数据,识别异常行为(如入侵、跌倒等),并及时发出警报,提高家庭安全性。 系…

英福康INFICON RGAs for the AMAT Endura 5500 课件PPT

英福康INFICON RGAs for the AMAT Endura 5500 课件PPT

uniapp+vue3实现音乐播放器,包含上一首、下一首、暂停、播放、下载音频、下载视频、进度条拖拽、歌词等

uni-app中实现音乐播放器 1、主要利用的是uni-app中提供的uni.createInnerAudioContext()来进行实现&#xff1b; 2、代码示例 &#xff08;1&#xff09;主页面代码展示 <template><view class"songDetailContainer"><view class"bg&quo…

记录uni-app横屏项目:自定义弹出框

目录 前言&#xff1a; 正文&#xff1a; 前言&#xff1a;横屏的尺寸问题 最近使用了uniapp写了一个横屏的微信小程序和H5的项目&#xff0c;也是本人首次写的横屏项目&#xff0c;多少是有点踩坑不太适应。。。 先说最让我一脸懵的点&#xff0c;尺寸大小&#xff0c;下面一…