zoukankan      html  css  js  c++  java
  • 文字渲染一探

    引子

    近一个月都在与字体打交道,查阅了不少资料。

    发现国内很少有这方面的一些资源,有点奇怪。

    故此,想稍微梳理一下这方面的一些资料以及信息,方便对这方面感兴趣的朋友参阅。

     

    文字渲染的组成

    文字渲染严格意义上来说包含几个主要的核心模块,分别是:

    1.字体光栅化 FreeType

    它是一个软件字体引擎,它被设计成小巧、高效、可高度定制和可移植,同时能够生成高质量的输出(字形图像)。它还可以用于图形库、显示服务器、字体转换工具、文本图像生成工具和许多其他产品。

     

    2.字体适配 Fontconfig

    主要用于配置、定制管理系统里的字体,简单的说就是通过给出的字体信息,例如粗体,斜体等,找到现有系统中最匹配的这些特征的字体文件。

     

    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

  • 相关阅读:
    有赞个性化推荐能力的演进与实践
    Doge.jpg 的背后是什么,你知道么?
    实操|如何将 Containerd 用作 Kubernetes runtime
    Linux 用键盘操作窗口
    Oracle中join left,join right,inner join,(+) 等
    sql之left join、right join、inner join的区别
    SQL中GROUP BY的用法
    Oracle CASE WHEN 用法介绍
    Oracle数据库面试题
    Oracle笔试题库之问答题篇-总共60道
  • 原文地址:https://www.cnblogs.com/cpuimage/p/13337475.html
Copyright © 2011-2022 走看看