引子
近一個月都在與字體打交道,查閱了不少資料,
發現國內很少有這方面的一些資源,有點奇怪,
故此,想稍微梳理一下這方面的一些資料以及資訊,方便對這方面感興趣的朋友參閱,
文字渲染的組成
文字渲染嚴格意義上來說包含幾個主要的核心模塊,分別是:
1.字體光柵化 FreeType
它是一個軟體字體引擎,它被設計成小巧、高效、可高度定制和可移植,同時能夠生成高質量的輸出(字形影像),它還可以用于圖形庫、顯示服務器、字體轉換工具、文本影像生成工具和許多其他產品,
2.字體適配 Fontconfig
主要用于配置、定制管理系統里的字體,簡單的說就是通過給出的字體資訊,例如粗體,斜體等,找到現有系統中最匹配的這些特征的字體檔案,
3.Unicode文本雙向演算法 FriBidi
主要用來轉換不同語系中存在的文本方向問題,例如右向左的文本, 翻轉后為左向右順序的文本,
4.文字塑形HarfBuzz
HarfBuzz是一種文字塑形布局引擎(text shaping library),它主要將Unicode轉換為格式正確且位置正確的字形輸出,
簡單地說就是用于適配全世界不同語言的文字編碼布局,
另一個非常知名庫是ICU,而HarfBuzz的實作中將其作為第三方庫引入
5.布局渲染Cairo或Skia Graphics Library
當你拿到字體字形的資料之后,毫無疑問,
肯定是需要一個布局渲染引擎把這些文字在對應的位置上畫出來,
在手機或者PC端的作業系統中我們看到的文字,是經過以上這個幾個步驟處理之后才能正常且正確地呈現出來,
而時至今日,文字已經沒辦法滿足大家在網路上一些表達上的需要,
從普通的文字,再到字符畫,再到如今各式各樣的emoji表情,
文字渲染這個領域已經有了更多新的需求和呈現,
那現代的文字渲染的架構是什么樣的呢?
我們來看下安卓的文字繪制架構圖:

此圖摘自(https://medium.com/mindorks/deep-dive-in-android-text-and-best-practices-part-1-6385b28eeb94)
我們看到,字體光柵化采用了FreeType,渲染采用了Skia,布局塑形采用了HarfBuzz和ICU,
他們最終通過一個名為Minikin庫向外部提供能力,
那Minikin是個什么東西,它到底干了些啥呢?
Minikin 是一個安卓中實作的一個文本布局庫,并且知名框架Flutter使用的libtxt布局引擎也是基于Minikin,
Minikin的代碼倉庫: https://android.googlesource.com/platform/frameworks/minikin/
從其源代碼中,可以大致看到,Minikin做了 字體管理,斷句斷行,emoji字符的判別,Unicode文本雙向演算法,布局以及測量等,
可謂是麻雀雖小五臟俱全,真的是一份非常值得深入學習的資源,
當然有一個非常不友好的地方就是,它依托著FreeType,Skia,HarfBuzz,ICU四大庫,
而這四大庫,其中任何一個庫學習起來都有夠受的,就別提一共4個,
但是,如果要做好文字渲染這件事情,這就是必須越過的四座大山,
那如何入門是好?
一般情況下,如果我們只做中英文的文字渲染,我們暫時不考慮 字體適配,Unicode文本雙向,文字塑形布局,
那只要把重心放FreeType和Skia上就足夠了,
也就是兩個步驟:
1. 加載字體
2. 畫出來
就是這樣簡單粗暴,
為了方便大家學習和理解這方面的知識,博主為大家準備了兩份代碼,
1.移除FreeType的libpng第三方庫,改用LodePng替代,主要是簡化編譯,
代碼倉庫地址:
https://github.com/cpuimage/freetype
這里要補充說明下,為什么FreeType用到了libpng,
因為大多數的emoji表情是將PNG格式的圖片直接嵌入到字體檔案里,
但是因為png格式的圖片體積太大,遷入到字體檔案后,
整個字體檔案過大,并且繪制還存在失真的問題,
為了解決上面提及的幾個問題,
最新的emoji字體采用的是SVG格式嵌入的思路,好處就是體積小,且無損,
但是對于開發者的壞處就是,將SVG光柵化為圖片,
至少需要一個svg引擎,操作起來真的麻煩,
而最新版的FreeType 2.10.2 還沒有支持svg格式,不過已經有人在嘗試擴展這個功能了,
詳情可參閱:
https://summerofcode.withgoogle.com/archive/2019/projects/6002250785226752/
2.簡易的文本繪制示例TinyText
這是博主將谷歌開源的一個物理引擎Tiny Differentiable Simulator中的文字繪制模塊單獨提取出來,
并采用第三方庫SDKpowervr-sdk-tools進行編譯開發,
目前僅支持在Windows64位環境下編譯,如果要適配其他作業系統,
自行替換第三方庫powervr-sdk的其他系統版本即可,
代碼倉庫地址:
https://github.com/cpuimage/TinyText
示例效果圖如下:

編譯環境可以參閱Windows下C,C++開發環境搭建指南
推薦一個可參閱學習的專案:
freetype-gl 這是一個非常值得參閱學習的專案,字體渲染涉及到的基本演算法,都有了,而且還是純C的代碼,
深入字體渲染之抗鋸齒
當然有繪制渲染,就肯定存在抗鋸齒的問題,
抗鋸齒有好幾種方案和思路,
有兩種主流的演算法:
-
Signed distance fields 有向距離場
關于距離場的演算法知識就不展開細說了,
大伙可以參閱這個鏈接了解一下 https://zhuanlan.zhihu.com/p/26217154
基于距離場演算法做抗鋸齒有個弊端,因為距離是有強弱的,
如果距離場設定的半徑過大,字體會呈現得過渡平滑,
細節丟失,換句話說全是鈍角沒有銳角,會模糊失真,
但如果設定的半徑過小,就沒有抗鋸齒的效果,
所以采用距離場是需要進行引數適配的,
看圖自行感受一下:

-
Vector textures 矢量紋理
思路是基于貝塞爾曲線進行繪制,
簡單地講就是將文字資訊轉為類似于svg格式的資訊結構進行矢量繪制,
好處自然就是矢量化無損,
壞處就是實作復雜,計算量大,
看圖自行感受一下:

文字渲染如果細講的話,很難三言兩句就講明白的,
所以博主這里為大家提供一些參考資料:
-
GPU text rendering with vector textures https://wdobbie.com/post/gpu-text-rendering-with-vector-textures/
-
Korok字體系統設計 https://zhuanlan.zhihu.com/p/36553076
-
Font Rendering is Getting Interesting https://aras-p.info/blog/2017/02/15/Font-Rendering-is-Getting-Interesting/
-
Drawing Text with Signed Distance Fields in Mapbox GL https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817
-
Techniques For Rendering Text With Webgl https://css-tricks.com/techniques-for-rendering-text-with-webgl/
-
Rendering Text in Metal with Signed-Distance Fields https://metalbyexample.com/rendering-text-in-metal-with-signed-distance-fields/
-
sdf-antialiasing https://drewcassidy.me/2020/06/26/sdf-antialiasing/
-
Font Bitmap vs SDF https://www.shadertoy.com/view/llK3Wm
- 2D distance functions https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
以上,權當拋磚引玉之用,
授人以魚不如授人以漁,
2020年,希望疫情早點結束,大家恢復正常的作業和生活,
世界和平,人們皆友愛,
若有其他相關問題或者需求也可以郵件聯系俺探討,
郵箱地址是: [email protected]
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/3622.html
標籤:C
