文本显示是任何软件最重要的功能之一。但是很少有同学去关注文本的底层运作原理。这个系列将会介绍什么是文本的一些逻辑,以及如何利用我们的WPF现有接口,对文本进行最大程度定制化。


首先我们要明确,对于软件布局渲染来说,无论是文本,图片还是其他控件,其根本操作都是在指定区域显示指定大小的特定图像。由此我们可以推出,软件要完成某个特定对象布局渲染,需要1、测量对象的指定大小以及可以用于布局渲染的空间大小;2、确认对象放置的位置;3、将对象信息交给渲染线程进行绘制。对于WPF来说,有一套特定的模板方法去处理该流程:Measure、Arrange、Render。而对于文本来说,在此之前还需要有一个过程——找到对应字体的字符。

找字符

我们知道对于特定的文字,只要其编码方式相同,对应的编码数值就是确定的。但是虽然文本的编码相同,但是其显示图像却可以多种多样。以“黄腾霄好瘦”为例,下图分别是宋体、楷体、华文行楷、隶书字体下的显示状态。我们可以看到,同样的文字,显示样式各不相同,因为其对应的字体不同。

1564369493419

什么是字体(FontFamily)

字体可以理解为一个图形字典,它提供了指定“字符编码”到“字符图形”的映射关系。在windows的字符映射表中,我们可以看到这种映射关系。所以我们就能够通过字体和字符编码找到对应文本的形状。

1564370263324

那么加粗和斜体是怎么做的呢?我们看下宋体情况下”黄腾霄好瘦”这些文字的常规、加粗和斜体的显示状态。这里为了大家能够看清楚,特地调大了字号。

1564370869353

看出些情况了么?这里揭晓答案。首先是加粗。加粗很简单,你可以理解就是在常规字体上使用同样前景色的笔迹进行了一次描边,于是它就变粗了。

1564371280980

那么斜体呢?我们加两个背景框看看。看出来了吧,实际上一个就是一个skewtransform的事情嘛。

1564371903990

真的这么简单么?当然不是,我们来看一个反例,下图是Minion Pro的常规和斜体呈现的字符。最明显的是其中的f字母,根本就是两个不同的图好吧,怎么可能使用简单的transform变过来。

1564383640711

OK,那怎么办呢?easy,再制造一套字符,专门表示斜体时的图案。

我们在字体预览和相关设置中,可以找到Minion Pro字体,可以看到,其常规和斜体实际对应着不同的字体文件

1564384088039

1564384219815

那么粗体加斜体怎么办?造!粗体有不同的粗细程度,bold,semibold,medium?造!字体还有FontStretch控制字体横向伸展……造!造!造!

所以你可以看到Minion Pro有10个字体文件组成。当然如果你愿意,可以针对每一种字体粗细(FontWeight),斜体(FontStyle)都造出一个字体。如果你不愿意,当然也可以通过一种字体,让系统通过描边和SkewTransform的方式造出其他字体。

所以FontFamily,FontWeight,FontStyle,FontStretch可以确定一个字符的形状

1564384395424

听着很美妙了是不是,那么有没有想过如果这个编码的字符没有在字体中找到怎么办?

都没有还玩个锤子呀,显示个框框!

如果这么做,一定会被骂死掉。我们期望是用户的输入最大可能正确呈现。而且每个字体开发者尽可能少地开发重复的字体。

以Microsoft Himalaya为例,这款字体是针对藏文显示的字体。但是里面没有包含中文、日文、俄文等语言的字符。那么如果在这种字体下显示中文字符会怎么样呢?

1564385949866

除了一点点向上的偏移,其余都显示正常。

1564386357816

这是为什么呢?实际上,当我们在一种字体中没有找到对应的字符时,我们会采用FallBack 方案,在包含个字符编码的字体中选择一个,作为备用字体进行渲染。所以如果你当前字体没有包含该编码字符,没有关系,只要你的系统中,有其他字体能够显示就OK。但是如果所有字体都无法显示的话,那就GG了

参考链接:

Typography in WPF - Microsoft Docs


本文会经常更新,请阅读原文: https://dotnet-campus.github.io//post/WPF%E6%96%87%E6%9C%AC(1)-%E5%BD%93%E6%98%BE%E7%A4%BA%E6%96%87%E6%9C%AC%E6%97%B6%E6%88%91%E4%BB%AC%E5%88%B0%E5%BA%95%E5%9C%A8%E5%81%9A%E4%BB%80%E4%B9%88(1).html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 dotnet 职业技术学院 (包含链接: https://dotnet-campus.github.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系