文字渲染一探

引子

近一個月都在與字體打交道,查閱了很多資料。css

發現國內不多有這方面的一些資源,有點奇怪。html

故此,想稍微梳理一下這方面的一些資料以及信息,方便對這方面感興趣的朋友參閱。android

 

文字渲染的組成

文字渲染嚴格意義上來講包含幾個主要的核心模塊,分別是:git

1.字體光柵化 FreeTypegithub

它是一個軟件字體引擎,它被設計成小巧、高效、可高度定製和可移植,同時可以生成高質量的輸出(字形圖像)。它還能夠用於圖形庫、顯示服務器、字體轉換工具、文本圖像生成工具和許多其餘產品。web

 

2.字體適配 Fontconfig算法

主要用於配置、定製管理系統裏的字體,簡單的說就是經過給出的字體信息,例如粗體,斜體等,找到現有系統中最匹配的這些特徵的字體文件。api

 

3.Unicode文本雙向算法 FriBidi服務器

主要用來轉換不一樣語系中存在的文本方向問題,例如右向左的文本, 翻轉後爲左向右順序的文本。網絡

 

4.文字塑形HarfBuzz

HarfBuzz是一種文字塑形佈局引擎(text shaping library),它主要將Unicode轉換爲格式正確且位置正確的字形輸出。

簡單地說就是用於適配全世界不一樣語言的文字編碼佈局。

另外一個很是知名庫是ICU,而HarfBuzz的實現中將其做爲第三方庫引入

 

5.佈局渲染CairoSkia 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的代碼。

 

深刻字體渲染之抗鋸齒

固然有繪製渲染,就確定存在抗鋸齒的問題。

抗鋸齒有好幾種方案和思路。

有兩種主流的算法:

  1. Signed distance fields 有向距離場

關於距離場的算法知識就不展開細說了,

大夥能夠參閱這個連接瞭解一下 https://zhuanlan.zhihu.com/p/26217154

基於距離場算法作抗鋸齒有個弊端,由於距離是有強弱的,

若是距離場設置的半徑過大,字體會呈現得過渡平滑,

細節丟失,換句話說全是鈍角沒有銳角,會模糊失真。

但若是設置的半徑太小,就沒有抗鋸齒的效果,

因此採用距離場是須要進行參數適配的。

看圖自行感覺一下:

 

 

  1. Vector textures 矢量紋理

思路是基於貝塞爾曲線進行繪製。

簡單地講就是將文字信息轉爲svg描述格式,

而後進行光柵化繪製。

好處天然就是矢量化無損。

看圖自行感覺一下:

 

 

文字渲染若是細講的話,很難三言兩句就講明白的。

 

因此博主這裏爲你們提供一些參考資料:

  1. GPU text rendering with vector textures https://wdobbie.com/post/gpu-text-rendering-with-vector-textures/

  2. Korok字體系統設計 https://zhuanlan.zhihu.com/p/36553076

  3. Font Rendering is Getting Interesting https://aras-p.info/blog/2017/02/15/Font-Rendering-is-Getting-Interesting/

  4. Drawing Text with Signed Distance Fields in Mapbox GL https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817

  5. Techniques For Rendering Text With Webgl https://css-tricks.com/techniques-for-rendering-text-with-webgl/

  6. Rendering Text in Metal with Signed-Distance Fields https://metalbyexample.com/rendering-text-in-metal-with-signed-distance-fields/

  7. sdf-antialiasing https://drewcassidy.me/2020/06/26/sdf-antialiasing/

  8. Font Bitmap vs SDF https://www.shadertoy.com/view/llK3Wm

  9. 2D distance functions https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm

 

以上,權當拋磚引玉之用。

授人以魚不如授人以漁。

 

2020年,但願疫情早點結束,你們恢復正常的工做和生活。

世界和平,人們皆友愛。

 

如有其餘相關問題或者需求也能夠郵件聯繫俺探討。

郵箱地址是: gaozhihan@vip.qq.com

相關文章
相關標籤/搜索