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優化工具
相關文章
相關標籤/搜索