1

我必须编写一些使用字体的代码。有没有很好的主题介绍让我开始?

4

1 回答 1

4

What every developer should know about fonts中有很好的介绍。

我已经复制了这里的帖子,但是很多帖子都依赖于特定的字体部分和图片,所以我强烈推荐上面的链接。

我最初认为使用字体会很简单。然而,正确处理字体最终成为 Windward Reports(我们的 XML 和 SQL 报告系统)中的一项重大工作。如果您要做的不仅仅是在表单中放置一行文本,那么细节就变得很重要。

字体和字形 那么什么是字体?从根本上说,字体是一系列字形。你认为像字母 A 这样的字符是一个字形。那么字体就是该字体中所有字母的一组字形。如果你得到 Helvetica 字体,他们所有的字形看起来都是一种方式。如果你得到 Times Roman 字体,它们看起来是另一个。每个都是该字体的一组字形。

现在我们需要介绍代码页的概念。代码页是从字符编号到特定字形的映射。程序最初将每个字符存储为一个字节。然后对于亚洲字符集,有 DBCS 系统(有些字符是 1 个字节,有些是 2 个)。今天的程序大多使用 Unicode,但网页往往是 UTF-8,它是一个多字节序列,最多可达 4 个字节。

为什么要提出编码?因为每种字体都有一个编码,其中字符编号 178 可能会根据字体使用的代码页返回非常不同的字形。大多数字体文件使用 Unicode,因此您在那里有一个标准,但许多程序仍然使用特定的代码页,该页被映射到字体。当您显示 ABC 并且字体为 Wingdings 时会发生这种情况,因此您会得到 。所以第一点是您需要确保您使用的编码匹配或映射到您使用的字体的编码。

它变得更加复杂。值为 0xE000 – 0xF8FF 的字符未定义。每种字体都可以制作他们想要的任何东西(一种用途是添加克林贡语脚本)。因此,根据定义,具有此范围内的值的字符与用于显示该字体的字体文件相关联。这是大多数符号类型字体的工作方式。

好的,所以你正在使用 Unicode,你的字体文件使用 Unicode,你给它传递了一个字符串,然后……字符串显示为空白。这是怎么回事?好吧,字体文件不需要任何给定字符的字形。符号字体不会有 ABC。欧洲和美国使用的大多数字体没有中文、日文或韩文字形。使用字体没有的字形并不是错误,但它不会显示任何内容,不是空白,而是什么都没有(即 0 点宽)。

如果您要显示代码页中不存在的字形,则如果您使用其中一个旧代码页,也可能会遇到类似的问题。在这种情况下,您需要映射到不同的代码页,至少对于该字符(这是 Word 过去处理这种情况的方式)。

字体家族字体分为几个不同的类别。首先是比例字体和等宽字体。在等宽字体中,所有字符的宽度完全相同。并且高度是一致的,因为所有小写字母与所有大写字母的高度相同。尽可能避免使用等宽字体,因为它们更难阅读。亚洲字体几乎都是等宽的,因为汉字的宽度和高度都相同,所以比例没有意义。另一方面,希伯来语和阿拉伯语几乎必须成比例。

接下来是字体,可以是衬线字体,您可以在笔画结束时获得东西,无衬线字体,您最终不会得到任何额外的东西,装饰性的字体超出正常范围,以及可以随机包含任何东西的符号,包括条形码匹配映射到字形的字符代码的 ASCII 数字。这只是西欧字母。

Fontmetrics 现在我们开始测量字体,通过字体,大多数(不是全部)是测量字形。用于字体的标准度量是点,虽然点的最初含义有很多历史,但对于计算机世界来说,它是 72 点 == 1 英寸。您有时还会看到 twip 代表点的二十分之一,因此 1440 缇 == 1 英寸。我们现在有了 EMU,其中 914400 个 EMU == 1 英寸(更多在这里)。如果您使用点,则需要使用浮点变量。缇通常可以作为整数,而动车组肯定是。

然后是字体磅值。这是一个完全任意的数字。把它想象成旧 CRT 显示器的对角线尺寸,实际尺寸接近您的预期,但从来不是那个数字。磅值决定了渲染字形的大小,但它在页面上没有特定的度量。

现在这里开始变得有趣了,fontmetrics。首先,一切都必须从基线开始衡量。从字体的任何其他部分工作都行不通——你会遇到重大问题。所以从那里开始。基线上方绘制的最高部分是上升,基线下方绘制的最低部分是下降,两者都是从基线测量的。

然后是两行文本之间的间距。这是一种字体设置,因为字体设计者决定了该字体的适当间距。这可以通过不同的方式返回,Windows 将其视为您放置在下一行上方的间距,返回从基线到基线的度量,而 Java 将其视为下一行之前的行下方的间距并仅返回此值。此行距是您在相似的单行距文本行之间放置的间距。如果间距大于单个间距,则添加到此值。

您通常希望获得字体的这些高度,而不是您显示的字符串中的字形字符串。为什么?因为如果一行是“we were wrox”——没有上升或下降,该行将被放置在更靠近段落中的其他行的位置,这看起来很奇怪。您还需要查看所有字体和磅值,因为如果某些文本较大,您必须使用较大的上升/下降/前导值。但仅适用于具有较大文本的行,而不适用于整个段落。同样,所有这些都是从基线测量的,这是处理混合字体/大小的唯一方法。

好的,高度需要一些工作,但它非常简单,但是宽度 - 这真的很有趣。有趣的是,我的意思是你必须让一切都恰到好处。从根本上说,除了固定宽度的字体,每个字形的宽度加起来并不等于所有一起渲染的字形的宽度。几乎从来没有。为什么?有几个原因:

• 字距调整是根据相邻字母放置字母的位置。这就是为什么 AB 保持不同而 tt 重叠很多的原因。• 拉丁字母中的一些字符组合被组合,例如ae 变成æ 和德语中的ss 变成ß。• 同一字符的希伯来文和阿拉伯文字形不同,具体取决于它是在单词的开头、中间还是结尾。在阿拉伯语的情况下,尤其是末端使用的字形往往比中间的字形更宽。所以ﺺ的宽度取决于它在字符串中的位置。◦双向字体有下面列出的另一个问题。•复杂的脚本,如Indic(印度)将在一个位置改变字形,由几个字符组成。所以一个三字符的字符串可以是 1 到 3 个字形宽的任何东西。很简单,你需要提供一个完整的、完全格式化的字符串,到您正在运行的平台提供的 fontmetrics API 以获取字符串的长度。这是一个昂贵的调用,因为字符串将被渲染到内存以确定长度,但没有其他方法可以准确。并且您必须使用与渲染时完全相同的设置进行测量。只要这些不匹配,我们就会发现差异足够大,以至于人眼可以分辨出来。测试代码的最佳方法是查看右对齐文本,因为渲染时通常必须获取字符串左端的基线位置,因此如果计算长度错误 - 它会显示。但是没有其他方法是准确的。并且您必须使用与渲染时完全相同的设置进行测量。只要这些不匹配,我们就会发现差异足够大,以至于人眼可以分辨出来。测试代码的最佳方法是查看右对齐文本,因为渲染时通常必须获取字符串左端的基线位置,因此如果计算长度错误 - 它会显示。但是没有其他方法是准确的。并且您必须使用与渲染时完全相同的设置进行测量。只要这些不匹配,我们就会发现差异足够大,以至于人眼可以分辨出来。测试代码的最佳方法是查看右对齐文本,因为渲染时通常必须获取字符串左端的基线位置,因此如果计算长度错误 - 它会显示。

双向文本 最后,我们遇到了双向文本(阿拉伯语和希伯来语)的问题。双向文本从右到左,除了数字和拉丁词从左到右。所以它是从右到左读的,然后在一个数字或拉丁文本序列上你跳到最左边的点,从左到右读回到你完成上一个希伯来语/阿拉伯语的地方,然后跳到拉丁文的开头/编号部分并从右到左返回。

对于何时应该进行这些转换,已经进行了大量研究。有方向性强的角色、方向性弱的角色和没有方向偏好的角色。你没有正确执行这些规则的祈祷。没有任何。但一切都没有丢失。几乎每个平台,包括 Java 和 Windows,都有一个 API,您可以在其中按读取顺序提供字符串,它会根据规则正确呈现它们。他们还有一个 API,用于告诉您每个字符的位置以及如果您想将插入符号 1 字符向前或向后移动,您应该移动到哪个字符。

无论文本如何,您都可以将此 API 用于所有字体渲染和插入符号移动,并且它可以正常工作 - 也适用于复杂的脚本。如果您不是针对 bi-di 或复杂脚本,那么开始使用它会有点痛苦,但如果您最终要在那里,最好开始使用它,这样您就不必重新构建您的代码。相信我,你真的不想重新架构(我不得不重新架构一次——哦!)。

警告 不要将 Windows 字体复制到 Linux 或其他操作系统。fontmetrics 往往是关闭的,文本会看起来关闭。我不知道 TrueType 应该是可移植的,但在实践中,就像 Java 在任何地方都编写一次调试一样,字体往往会在任何地方进行调整。从为您的平台优化字体的供应商处获取字体。

于 2010-12-04T19:02:33.053 回答