Xcode 12 支持 SVG

咱们的项目中使用到了大量的图片资源,其中绝大部分都是由简单线条组成的 icon。这些素材在 UI 设计初期就是以矢量图的形式构建的,所以很是适合使用 SVG 这样的矢量文件进行储存。目前 iOS 或 Android(配合Google Play)都使用了类 Slicing 技术,可以根据不一样设备自动选择合适的图片素材打进包里。而 Flutter 虽然在资源管理上实现了根据不一样屏幕分辨率密度自动选择合适的图片资源的功能,但 Flutter 自己还没法实现相似 Apple Slide 这样自动根据不一样设备下发不一样尺寸资源的能力,所以多套素材无疑会给 App 包大小带来不可小觑的压力。bash

咱们随机选取一个 icon 进行测试:app

Resource Format x1 x2 x3 Total
PNG 536 bytes 908 bytes 1321 KB 2765 bytes
SVG 1,896 bytes

咱们发现,得益于矢量图像的特性,SVG 格式无需像 PNG 同样为每一种分辨率都生成一套位图,所以只须要计算一个文件的大小,在磁盘占用大小上 SVG 有着绝对优点。这仍是在最大分辨率为 x3 的基础上的,随着超高分辨率屏幕和跨平台开发框架(Flutter、SwiftUI)的流行,为每套设备都切一套图的成本只会愈来愈高。框架

此外 PNG 还支持有损压缩,所以咱们通常会对 PNG 进行进一步压缩以压榨 App 的体积。不过不少人可能不了解,SVG 格式也是能够压缩的。编辑器

咱们将上图的 SVG 用文本编辑器打开,发现它使用了 XML 做为描述语言,并基于二维坐标系对矢量图形进行描述。他的头部每每会存在一些无用信息,包括转换软件遗留下的冗余信息。同时,同 js 压缩同理,咱们也能够经过去处格式化来进一步压缩文件大小。ide

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24pt" height="24pt" viewBox="0 0 24 24">
<g enable-background="new">
<clipPath id="cp0">
<path transform="matrix(1,0,0,-1,0,24)" d="M 0 24 L 24 24 L 24 0 L 0 0 L 0 24 Z " fill-rule="evenodd"/>
</clipPath>
<g clip-path="url(#cp0)">
<clipPath id="cp1">
<path transform="matrix(1,0,0,-1,0,24)" d="M -335 -613 L 40 -613 L 40 54 L -335 54 Z "/>
</clipPath>
<g clip-path="url(#cp1)">
<path transform="matrix(1,0,0,-1,0,24)" d="M -5 29 L 29 29 L 29 -5 L -5 -5 Z " fill="#ffffff" fill-opacity=".01"/>
</g>
</g>
<clipPath id="cp2">
<path transform="matrix(1,0,0,-1,0,24)" d="M -335 -613 L 40 -613 L 40 54 L -335 54 Z "/>
</clipPath>
<g clip-path="url(#cp2)">
<path transform="matrix(1,0,0,1,3.5,20.75)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#1f2329" d="M 0 .25 L 18 .25 "/>
</g>
<clipPath id="cp3">
<path transform="matrix(1,0,0,-1,0,24)" d="M 5.5 10.64008 L 5.5 7 L 9.158594 7 L 19.5 17.34593 L 15.84753 21 L 5.5 10.64008 Z "/>
</clipPath>
<g clip-path="url(#cp3)">
<clipPath id="cp4">
<path transform="matrix(1,0,0,-1,0,24)" d="M -335 -613 L 40 -613 L 40 54 L -335 54 Z "/>
</clipPath>
<g clip-path="url(#cp4)">
<path transform="matrix(1,0,0,-1,0,24)" d="M .5 26 L 24.5 26 L 24.5 2 L .5 2 Z " fill="#ffffff"/>
</g>
</g>
<clipPath id="cp5">
<path transform="matrix(1,0,0,-1,0,24)" d="M -335 -613 L 40 -613 L 40 54 L -335 54 Z "/>
</clipPath>
<g clip-path="url(#cp5)">
<path transform="matrix(1,0,0,1,5.5,3)" stroke-width="2" stroke-linecap="butt" stroke-linejoin="round" fill="none" stroke="#1f2329" d="M 0 10.35992 L 0 14 L 3.658594 14 L 14 3.654071 L 10.34753 0 L 0 10.35992 Z "/>
</g>
</g>
</svg>
复制代码

咱们使用了SVG优化工具,通过压缩,咱们能够很明显的看到,压缩后的字符数明显减小,压缩比达到了65%。虽然原理不是很复杂,但实际获得的压缩效果仍是很可观的。svg

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><clipPath id="cp0"><path transform="matrix(1 0 0 -1 0 24)" d="M0 24h24V0H0v24z" fill-rule="evenodd"/></clipPath><g clip-path="url(#cp0)"><clipPath id="cp1"><path transform="matrix(1 0 0 -1 0 24)" d="M-335-613H40V54h-375z"/></clipPath><g clip-path="url(#cp1)"><path d="M-5-5h34v34H-5z" fill="#fff" fill-opacity=".01"/></g></g><clipPath id="cp2"><path transform="matrix(1 0 0 -1 0 24)" d="M-335-613H40V54h-375z"/></clipPath><g clip-path="url(#cp2)"><path stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#1f2329" d="M3.5 21h18"/></g><clipPath id="cp3"><path transform="matrix(1 0 0 -1 0 24)" d="M5.5 10.64V7h3.659L19.5 17.346 15.848 21 5.5 10.64z"/></clipPath><g clip-path="url(#cp3)"><clipPath id="cp4"><path transform="matrix(1 0 0 -1 0 24)" d="M-335-613H40V54h-375z"/></clipPath><g clip-path="url(#cp4)"><path d="M.5-2h24v24H.5z" fill="#fff"/></g></g><clipPath id="cp5"><path transform="matrix(1 0 0 -1 0 24)" d="M-335-613H40V54h-375z"/></clipPath><g clip-path="url(#cp5)"><path stroke-width="2" stroke-linejoin="round" fill="none" stroke="#1f2329" d="M5.5 13.36V17h3.659L19.5 6.654 15.848 3 5.5 13.36z"/></g></svg>
复制代码
Resource Format x1 x2 x3 Total
PNG 326 bytes 654 bytes 567 KB 1547 bytes
SVG 1234 bytes

将两种格式都各自进行压缩操做后,会发现最终体积的差异其实不大。尤为是对于 iOS 或 Android(配合Google Play)这种支持 slicing 的原平生台,单个位图体积也要优于矢量图。 此外,位图的解析时间成本要低于矢量图(尤为是在复杂图像上)。而在 iOS 平台还会额外对 PNG 进行优化,所以 Apple 以前一直没有正式支持 SVG 资源。 不过在最新的 Xcode 12 中咱们惊讶的发现 Assets 已经支持 SVG 资源了。 wordpress

不过不要高兴的太早,由于咱们知道 Apple 早在 Xcode 6 就支持了矢量格式 PDF,但其实现原理仍是在编译过程当中将 PDF 动态生成三种尺寸的 PNG,实际展现的时候使用的仍是位图资源。 起色出如今了 iOS 13 上。SF Symbols 的出现让矢量图一会儿出如今了 Apple 平台的 C 位,连带着欲遮还羞的内部私有库 CoreSVG,让全部人都对原生 SVG 的支持抱有无限遐想。那此次 Xcode 12 对 SVG 的支持,使用的是传说中的 CoreSVG,仍是 PDF 的老把戏?接下俩咱们实操一下。
经过 Xcode 的 Debug View Hierarchy,咱们能够看到 Image 的 data 是 base64 编码的内容,有种一种不祥的气息。
经过对 data 进行解码,不出所料,Xcode 仍是将 SVG 转换成了 PNG。并且经过阅读 iOS 14 的 API,CoreSVG 依旧没有公开出来。

这个不痛不痒的功能,其实在以前版本的 Xcode 上就可以经过移花接木的方式曲线实现,并且还可以经过使用私有 API 的方式经过 CoreSVG 直接解析 SVG,不过不推荐这么作,会有被拒的风险。 虽然 Apple 已经在去年给出了 Symbol Image 方案,其本质也就是 SVG Path 的集合,也容许设计人员经过 SF Symbols App 设计自定义 icon,但这个学习成本可能不是每个设计人员可以达到的。工具

这个结果其实多少仍是挺让人失望的,由于隔壁 Android 早就开始支持 SVG 格式的资源了(虽然是阉割版),而咱们内部的 Flutter 项目也早早就使用上了 SVG。 我估计 Apple 是对 SVG 尚未充足的把握,毕竟 SVG 做为一个有着20年历史的古老格式,各类历史兼容性包袱、动画、性能等等,都是不能忽视的问题。Apple 对于自家的 SF Symbols 有着超强的控制力,可以保证 100% 的兼容性和性能,但你能保证大家的 UI 在画 icon 的时候是严格按照规范来实现的吗? 实际的状况可能比你想的要糟。性能

仍是拿咱们的 Flutter 项目来讲,咱们发现大量的 icon 并无严格按照轮廓来勾勒线条,而是使用了路径叠加等方式实现。这些问题不只会增大 SVG 文件体积,还会增长矢量数据到位图的转换复杂度。不过根据咱们的 Flutter 测试,对于简单的 icon ,目前的主流机型都不存在太大的解析压力。学习

我罗列了一下 SVG 格式目前可能存在的问题:

  1. 随着压缩技术的发展,位图格式(PNG、WebP、HEIF)的大小会愈来愈小,与 SVG 的差距会愈来愈小。
  2. 复杂图像转换为 SVG 的收益不大,甚至更低,尤为在解析速度上。
  3. 高质量的 SVG 资源创建在规范的构建上,不规范的 SVG 体积更大,解析效率更低。
  4. 目前不一样平台的 SVG 解析库多少都有必定兼容性问题,除了一些复杂效果以外,也不支持动画等特性。 虽然咱们暂时还没法为所欲为在 iOS 平台上用上 SVG,但相信矢量资源会随着跨平台、超高分辨率等技术的发展,逐渐成为一种主流格式。让咱们拭目以待。

参考:

  1. iOS端矢量图解决方案汇总(SVG篇)
  2. SVG精简压缩工具svgo简介和初体验
  3. SVG优化工具
相关文章
相关标签/搜索