课程 15 - 文本渲染
文本渲染是一个非常复杂的过程,State of Text Rendering 2024 中给出了非常详细的介绍,强烈推荐你阅读这篇综述文章。
在这节课中你将学习到以下内容:
- 什么是文本度量 FontMetrics
- 使用 SDF 绘制
对于习惯了使用浏览器提供的 Canvas 2D Drawing text 或 SVG 的开发者来说,文本渲染的复杂性可能超出了你的想象。下图来自 Modern text rendering with Linux: Overview,它展示了文本渲染的数据流,从文本到字形,再到光栅化,最后绘制到屏幕上。其中 OpenType 是目前最流行的字体格式。
基于我之前在 Web 端可视化项目中的经验,Text rendering in mapbox 可能更具有实操层面的指导意义,毕竟我们不会直接接触上述工具链中的绝大部分。但尽可能多了解上述流程,有助于你理解文本渲染的本质。
Shaping
什么是 Shaping 呢?下图来自 Text rendering in mapbox,简而言之就是放置一个个字符的位置,当然过程中需要考虑很多情况,例如遇到换行符:
下图来自 Modern text rendering with Linux: Overview
越来越多的应用选择在 Web 端使用 harfbuzzjs,详见:State of Text Rendering 2024
Using HarfBuzz on the web has been on the rise, first transpiled to JavaScript, and more recently cross-compiled to WebAssembly, through harfbuzzjs. Apps like Photopea, an online photo editor, use it that way. Crowbar by Simon Cozens is an OpenType shaping debugger web-app built using the HarfBuzz buffer-messaging API. Sploot is another web-app by Simon, a font inspector. Prezi and Figma also use HarfBuzz in their web-apps.
Line breaking
换行需要考虑很多情况,例如:
- 遇到了显式换行符
- 自动换行,同时让每一行尽可能保持接近的长度,详见:Beautifying map labels with better line breaking
BiDi
下图来自 Text layout is a loose hierarchy of segmentation
Improving Arabic and Hebrew text in map labels
HarfBuzz won't help you with bidirectionality.
Text layout is a loose hierarchy of segmentation
At this point, we have a run of constant style, font, direction, and script. It is ready for shaping. Shaping is a complicated process that converts a string (sequence of Unicode code points) into positioned glyphs. For the purpose of this blog post, we can generally treat it as a black box. Fortunately, a very high quality open source implementation exists, in the form of Harfbuzz.
HarfBuzz can tell you how wide a shaped piece of text is, which is useful input to a justification algorithm, but it knows nothing about paragraphs, lines or line lengths. Nor will it adjust the space between words to fit them proportionally into a line.
使用 SDF 绘制
FreeType 是字体渲染引擎
我们需要支持 CJK 这样的大文本量字符集,因此需要实时而非离线生成 SDF,详见:Text rendering in mapbox