[Tech] FontKit:字型拆包套件
對於任何一個已經封裝完成,也就是格式為 *.otf
或是 *.woff
的字型來說,想要將其逆向拆包,可以使用 Python 的 fontTools 工具,或是 javascript 的 Fontkit 套件——換句話說,如果想要在瀏覽器上進行拆包,便是 Fontkit 大展神威的時候。
安裝
|
|
Webfont 分析
在這裡,我們選擇 Google & Adobe 的思源系列(Noto)作為示範,畢竟可以算是目前最廣為人知的開源字型,沒有之一。以思源黑體繁體中文(Noto Sans CJK TC)為例,可以在 Google Font 裡選擇 想要顯示的字重(font weight),以 Medium 500 這個字重為例,在我們 select 之後,可以在旁邊的側欄裡看到一串 css 代碼:
|
|
只要把這段貼到 <head>
裡面,就可以讓網頁直接使用了。不過,我們想要了解的是,其背後究竟是如何實現的?
當我們直接用瀏覽器打開 url
裡面的 Stylesheet 網址後,會看到一大串被分割的 @font-face
,像是這樣的格式:
|
|
為什麼會出現這麼多的 @font-face
屬性?雖然「思源黑體」是 一套 字型,但因為其包含的字數太多了(全部共有 65536 個字)。裡面有很多罕用字,而且也不是每一個常用字都會出現在網頁上。如果我們的網頁內文沒有某某字符,卻還是把整包字型抓下來,就白白浪費了下載和等待的時間。
因此,Google 將一套字型拆分成多個子字型檔案(subset font),並且透過 unicode-range
的方式限制取用,只有當想要顯示的字,出現在某個 @font-face
裡指定的 unicode-range
範圍時,才會真的從伺服器端下載 src
的 *.woff
檔案;而那些沒有用到的字,自然而然就不需要浪費時間和空間載入了。
Emoji
同理,我們也可以用同樣的方法去查詢 Noto Color Emoji,在:
|
|
的 stylesheet 裡面,透過直連,找到像是這樣的東西:
|
|
接著,我們可以拿出 src 裡面的 woff 檔案,透過前天介紹的 Wakamai Fond 、或是上面提到的 fontkit,分析這個 *.woff2
的字型檔案:
|
|
這裡面就有我們想要的東西了。

Table
如 log 出來的結果所示,一個 OpenType 格式的檔案其實是由多個被稱作 table 的資料庫所組成。
舉例來説,和字型名稱、廠商、版權宣告、版本等有關的訊息,都會被放在 name
table 裡面:
|
|
而跟「替換」有關的 feature,像是我們提到的供 Emoji 使用的 ccmp feature,則是放在 GSUB
裡面:
|
|
至於彩色字型的 COLR/CPAL 的色版呢?則是在 COLR
與 CPAL
的 table 裡面:
|
|
有沒有看到一些很熟悉的東西呢?像是基本色盤(base-palette
)的數量(numPalettes
)、每個色盤有幾個顏色(numPaletteEntries
),所有色盤共有幾個顏色(numColorRecords
)。如果我們拿 前天的 Rocher 來拆包的話,就會得到 11 個色盤、每色盤 4 色、共 44 色,和 [Wakamaifondue](https://wakamaifondue.com/) 的分析一樣!
|
|
而各個色盤的顏色(RGBA),則可以透過 colorRecords
這個 array 得到:
|
|
有了字型資訊與色盤資訊,我們便有機會透過 @font-palette-values
屬性來玩顏色了。
實作
在這裡,我們還是以老朋友 Noto Color Emoji 為例,並再次請來我們的老朋友 🐬(U+1F42C
)為例,能透過這個網址直接抓取:
|
|
內容為一個 Stylesheet:
|
|
其中 src 來源的 woff2 檔案,就是 僅包含 🐬 的 Noto Color Emoji 字型檔。
網頁的構造
我們先寫一個超簡單的網頁來顯示這隻可愛的小海豚 🐬:
|
|
並按照 Google Font API 回傳的 stylesheet 設定:
|
|
此時,我們可以看到一隻可愛的海豚!

另一方面,藉由 FontKit 套件,讓我們直接拆開這個 僅包含 🐬 的 Noto Color Emoji 字型檔。
|
|
並印出該字型檔的色盤資訊:
|
|
太好了,我們現在知道了兩件事:
- 這隻小海豚便是由這 四個顏色 所組成的。
- 這 四個顏色與其對應的圖層編號。
在 DAY 19 的 OpenType Color Font:實作 裡,我們知道只要能替換色版的顏色與圖層編號,就能藉由 override-colors
取代原本的字符顏色,所以我們也可以對這隻小海豚 🐬 進行顏色覆寫的操作,舉例來説,將編號 2
的圖層由 rgba(54, 180, 225, 255)
的藍色換成 rgba(93, 172, 129, 1)
的綠色:
|
|
如此一來,我們得到了什麼呢?一隻綠色的海豚!

本文同步刊於 iThome。詳見DAY 21 | FontKit (1):字型拆包套件、DAY 22 | FontKit (2):CPLR 與 CPAL table。