SVG 檔案格式
Scalable Vector Graphics,以 XML 為基礎的向量影像格式。
- MIME 類型
- image/svg+xml
- 副檔名
- .svg
- 分類
- 圖片
Magic number(檔案簽章)
含有 `<svg` 元素的純文字 XML(前面通常會有 `<?xml`)。
關於 SVG 格式
SVG 用 XML 把影像描述成向量圖形,所以放大到任何尺寸都不會模糊,還能用 CSS 設定樣式與製作動畫。因為它是純文字,沒有二進位的 magic number — 靠開頭附近的 XML 宣告或 `<svg` 元素來辨識。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 3 | UTF-8 byte-order mark | EF BB BF,可有可無,而且是 XML 允許出現在宣告之前的唯一東西。少數比較舊的剖析器和某些伺服器設定至今仍會拒收它,所以它一再成為「明明合法的 SVG 卻畫不出來」的原因。 |
| 0 | 2 | UTF-16 byte-order mark | 小端序是 FF FE,大端序是 FE FF。跟 UTF-8 那個標記不同,這個不是可有可無的:XML 規定 UTF-16 內容必須帶 BOM。UTF-16 的 SVG 很罕見,而且會弄壞每一個假設「一個字元一個位元組」的工具。 |
| 0 | 5 | XML declaration opener | 3C 3F 78 6D 6C,也就是開啟宣告的那幾個字元。XML 規定它只要出現,就必須是整份文件最前面的東西 — 所以位移 0,或是在 UTF-8 BOM 後面的位移 3。對 UTF-8 內容來說它是選用的,這也是為什麼沒有偵測器能硬性要求它存在。 |
| 0 | 5 | DOCTYPE opener | 3C 21 44 4F 43。Illustrator 和 Inkscape 產出的舊檔案,開頭是一個指名 SVG 1.1 DTD 的 DOCTYPE。只有在既沒有 BOM 也沒有宣告時它才落在位移 0,否則就緊接在宣告後面。SVG 2 已經拿掉 DTD,所以新檔案不會帶。 |
| 0 | 4 | Root element start tag | 3C 73 76 67。只有在檔案沒有 BOM、沒有宣告、沒有 DOCTYPE、開頭也沒有註解時,它才會落在位移 0 — XML 允許這四樣東西全部排在它前面,所以這個位移是真的不固定。偵測器的做法是在前幾百個位元組裡找這個字串,而不是去測某個位置。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| GZIP | .svgz 是壓過 gzip 的 SVG,所以它開頭是 1F 8B 08,裡面完全沒有看得懂的標記。伺服器會配上 gzip 的 Content-Encoding 標頭送出,瀏覽器則透明地解壓縮;在 hex 編輯器裡它就是一個 gzip member,如果寫入端有填檔名,那個名字會以 .svg 結尾。 |
| XML | SVG 就是 XML,所以任何通用的 XML 測試都會通過,而且什麼也沒告訴你。唯一能分開兩者的是根元素的名字:第一個不是宣告、DOCTYPE、註解或處理指令的標籤,必須是 svg 元素。巢狀在別的根元素底下的 svg 元素,不構成一份 SVG 文件。 |
| HTML | HTML5 允許行內的 svg 元素,所以一個 HTML 頁面裡可能出現辨識 SVG 用的那串位元組。看根元素到底是什麼:開頭是 DOCTYPE html、或是 html 起始標籤,就代表這是一份剛好裝了一張圖的 HTML,而且必須以 text/html 而不是 image/svg+xml 提供。 |
| PNG | 在位元組層級不可能混淆 — 89 50 4E 47 對上一堆看得懂的文字 — 但實務上天天在混淆,因為好幾套設計工具的「匯出成 SVG」吐出來的 SVG,整份內容就是一個裝著 base64 PNG 的 image 元素。這個檔案確實是 SVG,裡面那張圖卻仍然是點陣圖,放大照樣糊。 |
常見的壞法
- 多出來的一個 & 符號。XML 採用嚴苛的錯誤處理,所以 href 屬性裡的網址只要有一個沒跳脫的 &,整份文件就不是良構的,瀏覽器會什麼都不畫,而不是把前面 95% 的圖畫出來。它每次都必須寫成 &。
- 命名空間不見了。把根元素上那個指向 http://www.w3.org/2000/svg 的 xmlns 屬性拿掉,檔案仍然是合法的 XML、也照樣在文字編輯器裡打得開,但在每個瀏覽器裡都是一片空白。手改過的 SVG 突然不能用,最常見的原因就是這個。
- 編碼對不上。宣告說是 UTF-8,檔案卻是用 Latin-1 或 Shift-JIS 存的。text 元素會變成亂碼,或是剖析器在第一段不合法的序列就中止 — 而值得檢查的位元組在 text 元素裡面,不在標頭那邊。
- 截斷。寫到一半的 svg 結束標籤是致命的良構性錯誤,所以不像被截斷的 PNG,這裡沒有半張圖可看。判斷方式在檔案結尾:完好的 SVG 以一個 svg 結束標籤收尾,通常後面還有一個換行。
- BOM 出現在不該出現的地方。擺在一個宣告了別種編碼的宣告前面就是衝突;而在被行內嵌進 HTML 頁面的 SVG 裡,那三個位元組會變成看得見的空白,把周圍的版面推歪。
這個格式現在還在用嗎
SVG 是網路唯一達成共識的向量影像格式,二十五年過去仍然沒有對手。圖示、logo、圖表、示意圖和插畫全部用 SVG 出貨,因為同一個檔案在任何像素密度下都是銳利的,還能從 CSS 改顏色;2012 年前後用來解同一個問題的圖示字型,現在基本上已經消失了。SVG 不適合的場合是照片類內容 — 把一張照片描邊向量化,做出來的檔案比原本那張 JPEG 更大也更慢畫 — 以及動輒上萬條路徑的美術稿,那時每個元素的 DOM 成本會蓋過檔案變小的好處。它同時也是一個活生生的攻擊面,因為 SVG 可以夾帶 script 和外部引用,所以從使用者那裡收進來的檔案,一定要先淨化過再送出去。
在這個站上打開 SVG 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 SVG 搞混的格式,可以比對它們的開頭位元組。