UWP 手绘视频创作工具技术分享系列 - SVG 的解析和绘制

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 原文:UWP 手绘视频创作工具技术分享系列 - SVG 的解析和绘制本篇作为技术分享系列的第一篇,详细讲一下 SVG 的解析和绘制,这部分功能的研究和最终实现由团队的 @黄超超 同学负责,感谢提供技术文档和支持。
原文: UWP 手绘视频创作工具技术分享系列 - SVG 的解析和绘制

本篇作为技术分享系列的第一篇,详细讲一下 SVG 的解析和绘制,这部分功能的研究和最终实现由团队的 @黄超超 同学负责,感谢提供技术文档和支持。 

首先我们来看一下 SVG 的文件结构和组成

SVG (Scalable Vector Graphics) 是一种可缩放矢量图形,使用 XML 格式来定义,是一种 W3C 标准,图像在放大或改变尺寸的情况下其图形质量不会有所损失。

下面是一个简单的 SVG 的文件结构例子:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>

从文件结构来看,SVG 确实是一种标准的 XML 格式,而里面的元素,从字面上来看,是一个坐标为(100,50),半径为40,填充色为红色,线条为黑色,线宽为2的圆形。下面我们来看看 SVG 文件里面的基本元素和属性:

1. 结构元素

<defs>, <g>, <svg>, <symbol>, <use>

2. 图形元素

<line>, <circle>, <ellipse>, <polygon>, <polyline>, <rect>, <path> 

这些标签相信大家都不陌生,几乎每种界面语言都有类似的标记。在 SVG 里,最常用的还是<path>, 用它可以表示前面所有的标签。 

3. 特殊元素

<image> :图片,源通常由 base64 string 或 url 表示。它通常出现在这种场景:通过 PhotoShop 编辑一张图片后,导出为 SVG 格式,这时文件里就存在 <image> 标签,之后再导入到 AI 中进行路径编辑,导出为 SVG 格式,就有了一张可以描绘路径,又包含 <image> 底图的 SVG 文件了。

<text> :文本,设置文字内容和字体字号等信息后,就可以在 SVG 中显示这些文字。 <text> 支持 transform 属性,可以旋转缩放文字,同时还支持 style, css 代码可以直接添加进来。

完整的元素列表参考这里:https://developer.mozilla.org/zh-CN/docs/Web/SVG/element

4. 元素的若干属性

opacity, fill, stroke, stroke-width, stroke-miterlimit, fill-opacity, stroke-opacity, fill-rule, stroke-dasharray, stroke-dashoffset, stroke-linecap, stroke-linejoin, transform

这些都不难理解,代表了元素的透明度,填充,线条,变换等,因为 SVG 是 W3C 标准,所以以上这些外观属性,在 CSS 中都有对应的属性。另外,SVG 还支持其他的属性类型,如动画事件/动画定时/关键帧动画/图形属性/过滤器等,十分强大。

完整的属性列表参考这里:https://developer.mozilla.org/zh-CN/docs/Web/SVG/attribute

来看一个例子:自上而下,分别包含了 两个矩形,一个圆形,一个椭圆,一条直线,一条折线,一个多边形和一条自定义 path。

<?xml version="1.0" standalone="no"?>
<svg width="200" height="250" version="1.1" viewBox="0 0 200 250" xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
  <rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
  <circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
  <ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
  <line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
  <polyline points="60,110 65,120 70,115 75,130 80,125 85,140 90,135 95,150 100,145"
      stroke="orange" fill="transparent" stroke-width="5"/>
  <polygon points="50,160 55,180 70,180 60,190 65,205 50,195 35,205 40 190 30 180 45 180"
      stroke="green" fill="transparent" stroke-width="5"/>
  <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
</svg>

这里对上面的示例代码做一些补充说明:

计量单位 width height x y 等没有显示指定单位,这时我们认为单位就是 px。也可以明确指定单位 in cm 等,这时会根据当前设备的环境来换算为 px 显示。

viewBox 定义了画布上可以显示的区域,格式为 “x y width height”,如上图的 viewBox=“0 0 200 250”,从(0,0)点开始,宽高 200 * 250的区域,SVG 的 width=“200”,height=“250”,所以当前缩放比是1. 如果 SVG width=“400” height=“500”,则会有两倍的放大效果。

path 和其他元素的对比 在 SVG 中 path 是最常用的元素,和 polyline 做对比,path 也可以通过 d 的设置完成一样的折线或曲线,而且只需要很少的点就可以创建平滑的曲线,但 polyline 需要设置大量的点才能达到平滑的效果。所以从制作难度和缩放效果看,path 是更好的选择。

接下来看一下 SVG 的绘制过程

首先说明绘制的两个基本原则:

1. 解析顺序和绘制顺序一致,都要遵守 XML 中元素的位置排列。借用上面的例子,SVG 中元素在 XML 中有固定的排列顺序,我们解析时会遵守这个顺序,绘制时同样也会遵守这个顺序。也就是说先出现的元素,会出现在绘制的底层,而后出现的元素,会出现在绘制的顶层,如果元素间位置有重叠,则会出现顶层元素遮挡底层元素的情况。

2. 子节点会继承父节点的一些属性,如 opacity,transform 等。这点在绘制时需要特别注意,opacity 等静态属性需要继承,而 transform 等属性需要做矩阵变换才能得到子节点最终 transform。

来画手绘视频中对 SVG 的处理过程

处理中遇到的一些特殊情况和处理

1、解析SVG文档时,忽略DTD验证

    虽然是 DTD 是 XML 解析的标准验证方式,但是很多工具制作的 SVG,DTD 会缺失,所以解析时应该忽略 DTD 验证,不然会直接造成解析错误

2、解析SVG文档时,一些元素的属性值可能有多种分隔/表明方式

    多边形的点集,元素的 transform,都是一个数字集合,集合的分割方式可能是 “空格”,“,” 也可能是其他符号,所以在解析时需要兼容多种分割方式。

    颜色的表示,长度单位等,也可能会出现多种形式,如颜色有已知颜色和颜色值等形式,都需要做兼容。

3、元素的某些属性会继承父级元素  

    transform,透明度等属性,都需要考虑父级元素的继承关系。transform 会复杂一些,transform [3*2] 的 矩阵,会包括缩放/平移/旋转 等信息,子元素的平移信息,需要和父级元素做缩放相乘后,再做平移。

4、元素属性的默认值

     很多工具导出的 SVG,是会忽略一些属性的,而这些属性如果没有值,我们是没办法正确显示的。所以我们需要针对它们设置默认值。例如 fill 默认应该是 none,stroke 默认是 black,stroke-width 默认为1px,fill-rule 默认为 nonzero。这里重点说一下 fill-rule,它分为 evenodd 和 nonzero 两种方式:

    EvenOdd:确定一个点是否位于填充区域内的规则,具体方法是从该点沿任意方向画一条无限长的射线,然后计算该射线在给定形状中因交叉而形成的路径段数。 如果该数为奇数,则点在内部;如果为偶数,则点在外部。

    Nonzero:确定一个点是否位于路径填充区域内的规则,具体方法是从该点沿任意方向画一条无限长的射线,然后检查形状段与该射线的交点。 从零开始计数,每当线段从左向右穿过该射线时加1,而每当路径段从右向左穿过该射线时减 1。 计算交点的数目后,如果结果为零,则说明该点位于路径外部。 否则,它位于路径内部。

5、解析顺序与渲染顺序,描边与填色的顺序

     解析顺序和渲染顺序必须一致,并且和 XML 中的顺序一致,否则会出现错误的遮挡现象和绘制顺序倒转。描边和填色的顺序,基本原则是,单个元素的描边完成后,操作填色,然后再操作下一个元素。当然这里的填色可以灵活控制,比如保存所有填色,等所有描边完成后,一次性填色。

6、包含<image>标签的绘制

    包含 <image> 标签的 SVG,处理起来会有些特殊的地方。这种 SVG 的存在,一般是画师通过 PS 编辑图片后,再导入 AI 中生成的 SVG。处理这种 SVG 的绘制时,基本思路是:解析 <image> 标签,当做 SVG 的底图,用一个透明遮罩挡住;然后解析后面的 <path> 标签,这是只需要解析 path 和 stroke,不需要 fill,用这里的 path 去涂抹底图,涂抹过的地方,透明遮罩失效,底图露出,就达到了涂抹出底图线条的目的。按照这个思路把底图涂抹出来,类似刮刮卡的感觉。

 

到这里,SVG 的基本知识、解析和绘制原理就介绍完了,当然这只是很基础的过程,在后面我们会整理出一些很特殊的 SVG 格式的解析和绘制思路,届时和大家分享,谢谢。

 

目录
相关文章
|
22天前
|
人工智能 JavaScript 数据可视化
Cursor 、v0 和 Bolt.new:当今 AI 编程工具的全面解析与对比
本文对 Cursor AI、v0 和 Bolt.new 三大 AI 编程工具进行了全面比较,分析其各自优势与局限性,帮助开发者在不同工作流中灵活应用。
139 8
Cursor 、v0 和 Bolt.new:当今 AI 编程工具的全面解析与对比
|
12天前
|
数据安全/隐私保护 流计算 开发者
python知识点100篇系列(18)-解析m3u8文件的下载视频
【10月更文挑战第6天】m3u8是苹果公司推出的一种视频播放标准,采用UTF-8编码,主要用于记录视频的网络地址。HLS(Http Live Streaming)是苹果公司提出的一种基于HTTP的流媒体传输协议,通过m3u8索引文件按序访问ts文件,实现音视频播放。本文介绍了如何通过浏览器找到m3u8文件,解析m3u8文件获取ts文件地址,下载ts文件并解密(如有必要),最后使用ffmpeg合并ts文件为mp4文件。
|
14天前
|
机器学习/深度学习 编解码 算法
深入解析MaxFrame:关键技术组件及其对视频体验的影响
【10月更文挑战第12天】随着流媒体服务和高清视频内容的普及,用户对于视频质量的要求越来越高。为了满足这些需求,许多技术被开发出来以提升视频播放的质量。其中,MaxFrame是一种旨在通过一系列先进的图像处理算法来优化视频帧的技术。本文将深入探讨构成MaxFrame的核心组件,包括运动估计、超分辨率重建以及时间插值算法,并讨论这些技术如何协同工作以改善视频播放效果。
29 1
|
23天前
|
域名解析 网络协议 安全
DNS查询工具简介
DNS查询工具简介
92 4
|
2月前
|
Python
命令行解析工具 argparse
命令行解析工具 argparse
43 14
|
13天前
|
存储 前端开发 JavaScript
前端模块化打包工具的深度解析
【10月更文挑战第13天】前端模块化打包工具的深度解析
|
14天前
|
JSON JavaScript 前端开发
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
52 0
|
21天前
|
程序员 开发者 Python
深度解析Python中的元编程:从装饰器到自定义类创建工具
【10月更文挑战第5天】在现代软件开发中,元编程是一种高级技术,它允许程序员编写能够生成或修改其他程序的代码。这使得开发者可以更灵活地控制和扩展他们的应用逻辑。Python作为一种动态类型语言,提供了丰富的元编程特性,如装饰器、元类以及动态函数和类的创建等。本文将深入探讨这些特性,并通过具体的代码示例来展示如何有效地利用它们。
23 0
|
24天前
|
人工智能 JavaScript 数据可视化
Cursor、v0 和 Bolt.new:当今 AI 编程工具的全面解析与对比
本文深入解析了 Cursor AI、v0 和 Bolt.new 三大 AI 编程工具的特点与应用场景。Cursor 适合日常编码与团队协作,v0 专注于 UI 原型设计,Bolt.new 擅长全栈原型开发。各工具在功能上互为补充,开发者可根据需求灵活选择,以提升工作效率。
249 0
|
19天前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
39 0

推荐镜像

更多