[学习笔记] Windows编程——GDI——(八)字体和文本

前言:

学习笔记,随时更新。如有谬误,欢迎指正。


说明:

  1. 红色字体为较为重要部分。
  2. 绿色字体为个人理解部分。

原文链接:https://learn.microsoft.com/en-us/windows/win32/gdi/fonts-and-text

8 字体和文本

  1. 字体用于在视频显示器和其他输出设备上绘制文本。字体和文本功能提供了安装、选择和查询不同字体的功能。

8.1 关于字体

8.1.1 字体元素

  1. 字体是具有共同设计的字符和符号的集合。这种设计的三个主要元素被称为字型、样式和大小。
8.1.1.1 字型
  1. 字型是指字体中字符和符号的特定特征,例如组成字符的粗细笔画的宽度以及衬线的存在或不存在。衬线体是在不相连笔划的两端的短交叉线。没有衬线的字体或字体通常称为无衬线字体。
8.1.1.2 样式
  1. 样式指的是字体的粗细和斜度。
8.1.1.3 大小
  1. 字号是一个不精确值。通常可以通过测量从小写 g 底部到相邻大写 M 顶部的距离来确定

  2. 字体的大小是以点( point )为单位来指定的。点是一英寸的 0.013837 。按照点系统的设计,通常的做法是将一个点近似为 1/72 英寸

8.1.2 字体族

  1. 字体族是一组具有共同笔画宽度和衬线特征的字体。有五种字体系列。第六个系列允许应用程序使用默认字体。下表描述了字体族。

    字体系列说明
    Decorative指定新颖字体。例如,古英语。
    Dontcare指定通用的族名称。当字体信息不存在或无关紧要时,使用此名称。使用默认字体。
    Modern指定带或不带衬线的等宽字体。等宽字体通常是现代的;例如 Pica , Elite 和 Courier New 。
    Roman指定带有衬线的比例字体。例如 Times New Roman 。
    Script指定设计成看起来像手写的字体;例如, Script 和 Cursive 。
    Swiss指定不带衬线的比例字体。例如, Arial 。
  2. 这些字体族对应于在 Wingdi.h 文件中找到的常量: FF_DECORATIVE 、 FF_DONTCARE 、 FF_MODERN 、 FF_ROMAN 、 FF_SCRIPT 和 FF_SWISS 。应用程序在创建字体、选择字体或查询有关字体的信息时使用这些常量。

  3. 一个家中的字体由大小( 10 号、 24 号等)和样式(常规、斜体等)来区分。

8.1.3 光栅、矢量、TrueType 和 OpenType 字体

  1. 应用程序可以使用四种不同类型的字体技术来显示和打印文本:光栅、矢量、 TrueType 和 OpenType 。

  2. 字体之间的差异反映了每个字符或符号的字型存储在各自的字体资源文件中的方式:

    • 在光栅字体中,字型是系统用来在字体中绘制单个字符或符号的位图。
    • 在矢量字体中,字型是一组线端点,这些线端点定义了系统用于在字体中绘制字符或符号的线段。
    • 在 TrueType 和 OpenType 字体中,字型是直线和曲线命令的集合以及提示的集合。
  3. 系统使用直线和曲线命令来定义 TrueType 或 OpenType 字体中字符或符号的位图轮廓。系统使用提示来调整线条的长度和用于绘制字符或符号的曲线的形状。这些提示和相应的调整是基于用于减少或增加位图大小的缩放量。OpenType字体相当于TrueType字体,OpenType字体除了 TrueType 字型定义之外还允许 PostScript 字型定义。

  4. 由于光栅字体中每个字型的位图是为特定的设备分辨率设计的,因此光栅字体通常被认为是与设备相关的矢量字体不依赖于设备,因为每个字型都存储为可伸缩行的集合。然而,矢量字体通常比光栅或 TrueType 和 OpenType 字体绘制得更慢。 TrueType 和 OpenType 字体提供了相对较快的绘制速度和真正的设备独立性。通过使用与字型相关的提示,开发人员可以将 TrueType 或 OpenType 字体中的字符向上或向下缩放,并且仍然保持其原始形状。

  5. 如前所述,字体的字型存储在字体资源文件中。字体资源文件实际上是一个只包含数据的 DLL ,没有代码。对于光栅字体和矢量字体,这些数据分为两部分:描述字体度量的头(信息)和字型数据。光栅或矢量字体的字体资源文件由 .fon 文件扩展名标识。对于 TrueType 和 OpenType 字体,每种字体都有两个文件:第一个文件包含相对较短的头(信息),第二个文件包含实际的字体数据。第一个文件由 .fot 扩展名标识,第二个文件由 .ttf 扩展名标识。

8.1.4 字体使用的字符集

  1. 所有字体都使用一个字符集。字符集包含标点符号、数字、大写字母和小写字母以及所有其他可打印字符。字符集的每个元素由一个数字标识。

  2. 使用的大多数字符集都是美国 ASCII 字符集的超集,该字符集定义了从 32 到 127 的 96 个数值的字符。字符集主要分为五大类: Windows 字符集、 Unicode 字符集、 OEM (原始设备制造商)字符集 、 符号字符集 、
    特定于供应商字符集 。

8.1.4.1 Windows 字符集
  1. Windows 字符集是最常用的字符集。它本质上等同于 ANSI 字符集。空白字符是 Windows 字符集中的第一个字符。它的十六进制值为 0x20 (十进制 32 )。 Windows 字符集的最后一个字符的十六进制值为 0xFF (十进制 255 )。

  2. 许多字体指定一个默认字符。每当请求一个不在字体中的字符时,系统就提供这个默认字符。许多使用 Windows 字符集的字体将句号( . )指定为默认字符。 TrueType 和 OpenType 字体通常使用左中括号作为默认字符。

  3. 字体使用一种叫做四分符的分隔符来分隔单词和对齐文本。大多数使用 Windows 字符集的字体都指定空白字符作为分隔符。

8.1.4.2 Unicode 字符集
  1. Windows 字符集使用 8 位来表示每个字符;因此,可以使用 8 位表示的最大字符数是 256 ( 2^8 )。这对于西方语言来说通常是足够的,包括法语、德语、西班牙语和其他语言中使用的变音符号。然而,东方语言使用成千上万个独立的字符,不能使用单字节编码方案进行编码。随着计算机商业的发展,双字节编码方案被开发出来,这样字符就可以用 8 位、 16 位、 24 位或 32 位序列来表示。这需要复杂的传递算法;即便如此,在两台不同的计算机上使用不同的代码集可能会产生完全不同的结果。

    为了解决多种编码方案的问题,开发了用于数据表示的 Unicode 标准。 Unicode 是一个 16 位字符编码方案,可以表示 65536 ( 2^16 )个字符,这足以包括当今计算机商业中的所有语言,以及标点符号、数学符号和扩展空间。 Unicode 为每个字符建立一个唯一的码,以确保字符翻译始终是准确的。

8.1.4.3 OEM 字符集
  1. OEM 字符集通常在全屏 MS-DOS 会话中用于屏幕显示。字符 32 到 127 在 OEM 、 U.S. ASCII 和 Windows 字符集中通常是相同的。 OEM 字符集中的其他字符( 0 ~ 31 和 128 ~ 255 )对应于全屏 MS-DOS 会话中可以显示的字符。这些字符通常与 Windows 字符不同。
8.1.4.4 符号字符集
  1. 符号字符集包含通常用于表示数学和科学公式的特殊字符。
8.1.4.5 特定于供应商的字符集
  1. 许多打印机和其他输出设备提供基于字符集的字体,这些字符集与 Windows 和 OEM 字符集不同,例如,扩展二进制编码十进制交换码( EBCDIC )字符集。要使用这些字符集之一,打印机驱动程序将从 Windows 字符集转换为特定于供应商的字符集。

8.1.5 字体安装和删除

  1. 只有字体驻留在指定设备上或安装在系统字体表中时,应用程序才能使用该字体来绘制文本。字体表是一个内部数组,用于标识应用程序可用的所有非设备字体。应用程序可以通过调用 EnumFontFamiliesChooseFont 函数来查询当前安装在设备上或存储在内部字体表中的字体名称。

  2. 要临时安装字体,请调用 AddFontResourceAddFontResourceEx 。这些函数加载存储在字体资源文件中的字体。但是,这是临时安装,因为重新启动后字体将不存在。

    若要安装在系统重启后仍保留的字体,请使用以下方法之一:

    • 转到控制面板,单击字体图标,然后从文件菜单中选择安装新字体。即使在重新启动之前,应用程序也可以使用该字体。但是,在终端服务器的情况下,字体对当前会话可用,但对其他会话不可用,直到重新启动之后。
    • 将字体复制到 %windir%\fonts 文件夹中。然后,转到控制面板并单击字体图标,或调用 AddFontResourceAddFontResourceEx 。即使在重新启动之前,应用程序也可以使用该字体。但是,在终端服务器的情况下,字体对当前会话可用,但对其他会话不可用,直到重新启动之后。如果只将字体拷贝到 %windir%\fonts 文件夹中,则该字体只有在系统重启后才可用。
  3. 当应用程序完成使用已安装的字体时,它必须通过调用 RemoveFontResource 函数来删除该字体。

    从 %windir%\fonts 文件夹以外的位置安装的字体在任何激活会话(包括会话 0 )中加载时都不能修改。因此,任何更改、替换或删除的尝试都将被阻止。如果需要修改字体:

    • 临时字体仅在当前会话中加载。在尝试任何字体修改之前,调用 RemoveFontResource 来强制当前会话卸载字体。
    • 永久字体在重新启动后仍然安装,并由所有创建的会话加载。调用 RemoveFontResource 来强制当前会话卸载字体。然后,在字体注册表项( HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts )中找到并删除与字体相关的注册表值。最后,重新启动机器以确保在任何会话中都没有加载字体。重新启动后,继续进行字体修改/删除。
  4. 每当应用程序调用添加和删除字体资源的函数时,它也应该调用 SendMessage 函数并向系统中的所有顶级窗口发送 WM_FONTCHANGE 消息。此消息通知其他应用程序,内部字体表已被某个应用程序更改(添加或删除字体)。

8.1.6 多个资源文件中的字体

  1. 通常,字体包含在单个字体资源文件中。但是,某些字体的信息分散在几个文件中。例如,Type 1 多个主字体需要两个文件:

    • .pfm :用于字体度量。
    • .pfb :用于字体位。
  2. 要从多个文件中添加字体到系统中,请使用 AddFontResourceAddFontResourceEx 函数。这些函数中的 lpszFilename 参数必须指向一个字符串,该字符串包含由竖条或管道( | )分隔的文件名。例如,为 Type 1 字体指定 abcxxxxx.pfm 和 abcxxxxx.pfb ,使用字符串“ abcxxxxx.pfm | abcxxxx.pfb "。

  3. AddFontResourceExAddFontResource 的不同之处在于,调用 AddFontResourceEx 的应用程序可以将字体指定为私有字体或不可枚举字体。

  4. 要从内存映像中添加字体,请使用 AddFontMemResourceEx 。这允许应用程序使用嵌入在文档或网页中的字体。

  5. 要删除来自多个资源文件的字体,调用 RemoveFontResourceRemoveFontResourceEx ,具体取决于用于添加字体的函数。必须指定用于添加字体的相同标志。要删除从内存映像中添加的字体,请使用 RemoveFontMemResourceEx

  6. 使用来自多个字体资源文件的字体与使用来自单个资源文件的字体的方法是相同的。

8.1.7 字体创建和选择

  1. “字体通用”对话框简化了创建和选择字体的过程。通过初始化 CHOOSEFONT 结构并调用 ChooseFont 函数,应用程序可以支持以前需要许多行自定义代码的相同字体选择接口。(有关“字体通用”对话框的详细信息,请参见“通用对话框库”。)
8.1.7.1 用户选择
  1. 大多数字体创建和选择操作都涉及到用户。例如,文字处理应用程序允许用户为标题、脚注和正文选择唯一的字体。在用户使用字体对话框选择字体并按下 OK 按钮之后, ChooseFont 函数用请求字体的属性初始化 LOGFONT 结构的成员。要将这种字体用于文本输出操作,应用程序必须首先创建一个逻辑字体,然后在其设备上下文中选择该字体。逻辑字体是应用程序提供的对理想字体的描述。开发人员可以通过调用 CreateFontCreateFontIndirect 函数来创建逻辑字体。在这种情况下,应用程序将调用 CreateFontIndirect 并提供一个指向由 ChooseFont 初始化的 LOGFONT 结构的指针。一般来说,调用 CreateFontIndirect 更有效,因为 CreateFont 需要几个参数,而 CreateFontIndirect 只需要一个指向 LOGFONT 的指针。

  2. 在应用程序实际开始使用逻辑字体绘制文本之前,它必须从设备内部存储的字体和其资源已被加载到操作系统中的字体中找到最匹配的字体。存储在设备或操作系统中的字体称为物理字体。查找与指定的逻辑字体最接近的物理字体的过程称为字体映射。当应用程序调用 SelectObject 函数并提供标识逻辑字体的句柄时,就会发生此过程。字体映射是通过使用内部算法来执行的,该算法将请求的逻辑字体的属性与可用的物理字体的属性进行比较。

    当字体映射器算法完成搜索并确定最接近的可能匹配时, SelectObject 函数返回,应用程序可以开始用新字体绘制文本。

    SetMapperFlags 函数指定字体映射器算法是否只搜索长宽比与物理设备匹配的物理字体。设备的宽高比是由该设备上像素的宽度和高度形成的比率。

  3. 系统字体(也称为 shell 或默认字体)是用于标题栏、菜单和对话框中的文本的字体。

8.1.7.2 特殊字体选择注意事项
  1. 尽管大多数字体选择操作都涉及用户,但在某些情况下,情况并非如此。例如,开发人员可能希望在应用程序中使用唯一的字体来绘制控件窗口中的文本。要选择适当的字体,应用程序必须能够确定可用的字体,创建描述其中一种可用字体的逻辑字体,然后将该字体选择到适当的设备上下文中。

    应用程序可以通过使用 EnumFontsEnumFontFamilies 函数枚举可用的字体。推荐使用 EnumFontFamilies ,因为它枚举了与族名相关的所有样式。这对于具有许多或不寻常样式的字体以及跨越国际边界的字体非常有用。

    一旦应用程序枚举了可用字体并找到了适当的匹配项,它就应该使用字体枚举函数返回的值来初始化 LOGFONT 结构的成员。然后它可以调用 CreateFontIndirect 函数,传递给它一个指向初始化的 LOGFONT 结构的指针。如果 CreateFontIndirect 函数成功,应用程序就可以通过调用 SelectObject 函数来选择逻辑字体。在初始化 LOGFONT 结构的成员时,一定要在 lfCharSet 成员中指定一个特定的字符集。该成员在字体映射过程中很重要,如果没有正确初始化该成员,结果将不一致。如果在 LOGFONT 结构的 lfFaceName 成员中指定字体名称,请确保 lfCharSet 值与 lfFaceName 中指定的字体的字符集匹配。例如,如果要选择 MS Mincho 字体,则必须将 lfCharSet 设置为预定义值 SHIFTJIS_CHARSET 。

  2. 许多东亚语言的字体有两种字型名称:英文名称和本地化名称。 CreateFontCreateFontIndirectCreateFontIndirectEx 采用与语言匹配的系统区域设置的本地化字型名称,但它们采用所有其他系统区域设置的英文字型名称。最好的方法是尝试一个名字,如果失败,再尝试另一个。注意,如果系统语言环境与字体的语言不匹配, EnumFontsEnumFontFamiliesEnumFontFamilies 将返回英文字体名称。从 Windows 2000 开始,这不再是一个问题,因为 CreateFontCreateFontIndirectCreateFontIndirectEx 的字体映射器可以识别任何一种字型名称,而不管语言环境如何。

8.1.8 内嵌字体

  1. 嵌入字体是将文档及其包含的字体捆绑到一个文件中以便传输到另一台计算机的技术。嵌入字体可保证在传输文件中指定的字体将出现在接收该文件的计算机上。然而,并非所有字体都可以从一台计算机移动到另一台计算机,因为大多数字体一次只能授权给一台计算机使用。只能嵌入 TrueType 和 OpenType 字体。

  2. 只有当用户请求时,应用程序才应该在文档中嵌入字体。应用程序不能与包含嵌入字体的文档一起分发,应用程序本身也不能包含嵌入字体。当应用程序以任何格式分发字体时,必须承认字体所有者的专有权利。

  3. 嵌入任何不允许嵌入的字体或未遵守以下关于嵌入字体的指导原则,可能违反字体供应商的专有权利或用户许可协议。字体的许可证可能只授予在目标计算机上安装和使用字体的读/写权限。或者该许可证可能会授予只读权限。只读权限允许目标计算机查看和打印文档(但不能修改);具有只读嵌入字体的文档本身是只读的。只读嵌入字体可能无法从文档中解绑定并安装在目标计算机上。

  4. 应用程序可以通过调用 GetOutlineTextMetrics 函数并检查 OUTLINETEXTMETRIC 结构的 otmfsType 成员来确定许可证状态。如果设置了 otmfsType 的第 1 位,则不允许嵌入字体。如果第 1 位是空的,则字体可以嵌入。如果设置了第 2 位,则表示只读嵌入。

  5. 要嵌入 TrueType 字体,应用程序可以使用 GetFontData 函数读取字体文件。将 GetFontData 的 dwTable 和 dwOffset 参数设置为 0L ,将 cbData 参数设置为 1L ,确保应用程序从一开始读取整个字体文件。

  6. 有几个函数可用于嵌入 OpenType 字体,具体取决于字符宽度和字体数据所在的位置。要在设备上下文中嵌入 OpenType Unicode 字体,应用程序可以使用 TTEmbedFont 。要嵌入 OpenType UCS-4 字体驻留在设备上下文中,应用程序可以使用 TTEmbedFontEx 。要在字体文件中嵌入 OpenType Unicode 字体,应用程序可以使用 TTEmbedFontFromFile 。有关 OpenType 字体嵌入的其他信息,请参阅字体嵌入参考

  7. 在应用程序查找字体数据之后,它可以使用任何适用的格式将数据存储在文档中。大多数应用程序在文档中建立字体目录,列出嵌入的字体以及嵌入是读/写还是只读。应用程序可以使用 OUTLINETEXTMETRIC 结构的 otmpStyleName 和 otmFamilyName 成员来识别字体。

  8. 如果为嵌入字体设置了只读位,则应用程序必须在将字体数据与文档一起存储之前对其进行加密。加密方法不必复杂;例如,使用 XOR 操作符将字体数据与应用程序定义的常量组合起来就足够了,而且速度很快。

8.2 关于文本输出

  1. 文本输出是客户端区域中最常见的图形输出类型,应用程序以不同的方式使用它。文字处理和桌面应用程序创建带有格式化文本的文档;电子表格应用程序使用文本、数字和符号来指定公式、标签列和列表值;数据库应用程序使用文本创建记录和显示查询, CAD 应用程序使用文本标记对象和显示尺寸。

  2. 有一些函数可以在应用程序的客户端区域和打印纸上格式化和绘制文本。这些函数可以分为两类:格式化文本(或准备输出)的函数和实际绘制文本的函数。格式化功能包括对齐文本、设置字符间距、设置文本和文本背景颜色以及对齐文本。绘制函数绘制单个字符(或符号)或整个文本字符串。

  3. 在 Windows 中工作时,硬换行符使用回车负( \r\n )。

8.2.1 设置文本格式

  1. 格式化函数可以分为三类:为设备上下文查询或设置文本格式化属性的函数,查询字符宽度的函数,以及查询字符串宽度和高度的函数。
8.2.1.1 文本格式化属性
  1. 应用程序可以使用六个函数来设置设备上下文的文本格式属性: SetBkColorSetBkMode , SetTextAlign , SetTextCharacterExtraSetTextColorSetTextJustification 。这些函数影响文本对齐方式、字符间距、文本对齐以及文本和背景颜色。此外,还可以使用其他六个函数来查询任何设备上下文的当前文本格式属性: GetBkColorGetBkModeGetTextAlignGetTextCharacterExtraGetTextColorGetTextExtentPoint32
8.2.1.1.1 文本对齐方式
  1. 应用程序可以使用 SetTextAlign 函数来指定系统在调用绘制函数时应该如何定位文本字符串中的字符。此函数可用于定位标题、页码、标注等。系统通过将字符串周围的假想矩形上的参考点与当前光标位置或作为参数传递给文本绘制函数之一的点对齐来定位文本字符串。 SetTextAlign 函数允许应用程序指定这个参考点的位置。备上下文的默认文本对齐方式是围绕文本的假想矩形的左上角。应用程序可以通过调用 GetTextAlign 函数来查询任何设备上下文的当前文本对齐设置。
8.2.1.1.2 字符间间距
  1. 应用程序可以使用 SetTextCharacterExtra 函数来更改指定设备上下文中所有文本输出操作的字符间间距。任何设备上下文的默认字符间间距值为零。应用程序可以通过调用 GetTextCharacterExtra 函数来查询设备上下文的当前字符间间距值。
8.2.1.1.3 (行)文本对齐
  1. 应用程序可以使用 GetTextExtentPoint32SetTextJustification 函数对一行文本进行对齐。文本对齐是任何桌面及大多数文字处理应用程序中的常见操作。 GetTextExtentPoint32 函数计算文本字符串的宽度和高度。在计算宽度之后,应用程序可以调用 SetTextJustification 函数,在文本行的每个单词之间分配额外的间距。
8.2.1.1.4 文本和背景色
  1. 应用程序可以使用 SetTextColor 函数设置在其窗口的客户端区域中绘制的文本的颜色,以及在彩色打印机上绘制的文本的颜色。应用程序可以使用 SetBkColor 函数来设置出现在每个字符后面的颜色,并使用 SetBkMode 函数来指定系统应该如何将所选背景颜色与视频显示器上的当前颜色或颜色混合。

  2. 显示设备上下文的默认文本颜色是黑色;默认背景色为白色;默认的背景模式是 OPAQUE 。应用程序可以通过调用 GetTextColor 函数来查询设备上下文的当前文本颜色。应用程序可以通过调用 GetBkColor 函数来查询设备上下文的当前背景颜色,通过调用 GetBkMode 函数来查询当前背景模式。

8.2.1.2 字符宽度
  1. 应用程序在执行诸如将文本字符串匹配到页面或列宽度之类的任务时需要查询字符宽度数据。应用程序可以使用四个函数来查询字符宽度数据。其中两个函数查询字符前进宽度,另外两个函数查询实际字符宽度数据。

  2. 应用程序可以使用 GetCharWidth32GetCharWidthFloat 函数来查询文本字符串中单个字符或符号的前进宽度。前进宽度是视频显示器上的光标或打印机上的打印头在打印文本串中的下一个字符之前必须前进的距离。 GetCharWidth32 函数以整数值的形式返回前进宽度。如果需要更高的精度,应用程序可以使用 GetCharWidthFloat 函数来查询。

  3. 应用程序可以通过使用 GetCharABCWidthsGetCharABCWidthsFloat 函数来查询实际字符宽度数据。 GetCharABCWidthsFloat 函数适用于所有字体。 GetCharABCWidths 函数只适用于 TrueType 和 OpenType 字体。

    A 间距是在放置字符之前要添加到当前位置的宽度。 B 间距是字符本身的宽度。 C 间距是字符右侧的空白。总推进宽度通过计算 A+B+C 的和来确定。字符单元是一个假想的矩形,它包围着字体中的每个字符或符号。因为字符可以悬在字符单元的上方或下方,所以 A 和 C 增量中的一个或两个都可以是负数(示意图详见字符宽度)。

8.2.1.3 字符串宽度和高度
  1. 除了查询单个字符的字符宽度数据外,应用程序还需要计算整个字符串的宽度和高度。有两个函数查询字符串宽度和高度测量值: GetTextExtentPoint32GetTabbedTextExtent 。如果字符串不包含制表符,应用程序可以使用 GetTextExtentPoint32 函数来查询指定字符串的宽度和高度。如果字符串包含制表符,应用程序应该调用 GetTabbedTextExtent 函数。

  2. 应用程序可以使用 GetTextExtentExPoint 函数进行换行操作。此函数返回指定字符串中适合指定空格的字符数。

8.2.1.3.1 字体升序和降序
  1. 一些应用程序通过使用字体的最大升序和降序来确定不同大小的文本行之间的行间距。应用程序可以通过调用 GetTextMetrics 函数查询这些值,然后检查 TEXTMETRIC 的 tmAscent 和 tmDescent 成员。

  2. 最大的上升和下降与排版的上升和下降是不同的。在 TrueType 和 OpenType 字体中,排版的上升和下降通常是字形的顶部和底部。应用程序可以通过调用 GetOutlineTextMetrics 函数并检查 OUTLINETEXTMETRIC 结构的 otmMacAscent 和 otmMacDescent 成员中的值来查询 TrueType 或 OpenType 字体的排版升序和降序。

  3. NEWTEXTMETRICOUTLINETEXTMETRIC 结构中返回的垂直文本度量值之间的差异见图“字体升序和降序”。(以 otm 开头的名称是 OUTLINETEXTMETRIC 结构的成员。)

8.2.1.3.2 字体尺寸
  1. 应用程序可以通过调用 GetOutlineTextMetrics 函数来查询 TrueType 或 OpenType 字体的物理尺寸。应用程序可以通过调用 GetTextMetrics 函数来查询任何其他字体的物理尺寸。要确定输出设备的尺寸,应用程序可以调用 GetDeviceCaps 函数。 GetDeviceCaps 返回物理尺寸和逻辑尺寸。

  2. 逻辑英寸是系统用来在屏幕上显示易读字体的一种度量,大约比物理英寸大 30% 到 40% 。逻辑英寸的使用排除了屏幕和打印机输出之间的精确匹配。开发人员应该意识到,屏幕上的文本不仅仅是页面上文本的缩放版本,特别是当图形被合并到文本中时。

8.2.2 绘制文本

  1. 在应用程序选择合适的字体,设置所需的文本格式选项,并为文本字符串计算必要的字符宽度和高度值之后,就可以通过调用任何文本输出函数开始绘制字符和符号: DrawTextDrawTextExExtTextOutPolyTextOutTabbedTextOutTextOut

  2. 当应用程序调用这些函数之一时,操作系统将调用传递给图形引擎,图形引擎再将调用传递给适当的设备驱动程序。在设备驱动程序级别,所有这些调用都由对驱动程序自己的 ExtTextOutTextOut 函数的一个或多个调用来支持。通过调用 ExtTextOut ,应用程序将获得最快的执行速度,这将迅速转换为对设备的 ExtTextOut 调用。然而,在某些情况下,应用程序应该调用其他三个函数之一;例如,要在指定矩形区域的边界内绘制多行文本,调用 DrawText 会更有效。要创建具有文本列的多列表,调用 TabbedTextOut 更为有效。

8.2.3 复杂脚本

  1. 虽然前面讨论的函数适用于许多语言,但它们可能无法处理复杂脚本的需要。复杂的脚本是一种语言,其打印形式不是以简单的方式呈现的。例如,复杂的脚本可能允许双向呈现、字形的上下文塑造或组合字符。由于这些特殊要求,对文本输出的控制必须非常灵活。

  2. 显示文本的函数 TextOutExtTextOut , TabbedTextOutDrawTextGetTextExtentExPoint 已经扩展到支持复杂的脚本。一般来说,这种支持对应用程序是透明的。但是,应用程序应该将字符保存在缓冲区中,并一次显示整行文本,以便复杂的脚本塑造模块可以使用上下文重新排序并正确生成字形。此外,由于字形的宽度可能因上下文而异,应用程序应该使用 GetTextExtentExPoint 来确定行长度,而不是使用缓存的字符宽度。

  3. 复杂的脚本感知应用程序应该考虑为其应用程序添加对从右到左读取顺序和右对齐的支持。

  4. 还可以使用 Uniscribe 处理复杂的脚本。Uniscribe 是一组允许对复杂脚本进行精细控制的函数。有关更多信息,请参见 Uniscribe处理复杂脚本

8.2.4 ClearType 抗锯齿

  1. Microsoft ClearType 抗锯齿是一种平滑方法,它比传统的抗锯齿提高了字体显示分辨率。它极大地提高了带有数字接口的彩色 LCD 显示器的可读性,比如笔记本电脑和高质量的平板桌面显示器。在 CRT 屏幕上的可读性也有所提高。

    然而, ClearType 依赖于 LCD 条纹的方向和顺序。目前, ClearType 仅对具有 RGB 顺序的垂直条纹的 LCD 实现。这对平板电脑的影响尤其大,因为平板电脑的显示屏可以朝任何方向移动,而且平板电脑的屏幕可以从横向切换到纵向。

  2. 要激活 ClearType 反锯齿,先调用 SystemParametersInfo 打开字体平滑,然后再调用 SystemParametersInfo 来设置平滑类型为FE_FONTSMOOTHINGCLEARTYPE 。代码如下所示:

    SystemParametersInfo(SPI_SETFONTSMOOTHING,
                     TRUE,
                     0,
                     SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
    SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE,
                     0,
                     (PVOID)FE_FONTSMOOTHINGCLEARTYPE,
                     SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); 
    
  3. 可以通过更改 ClearType 算法中使用的对比度值来调整文本的外观。 默认值为 1400 ,但可以是 1000 到 2200 的任何值。若要更改对比度,请调用 SystemParametersInfo 来更改 SPI_SETFONTSMOOTHINGCONTRAST 值。代码如下所示:

    SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST,
                     0,
                     (PVOID)1600,
                     SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); 
    
  4. CreateFont 中的 fdwQuality 参数和 LOGFONT 的 lfQuality 成员接受 CLEARTYPE_QUALITY 标志。使用此标志创建的字体的光栅化将使用 ClearType 栅格器。此标志对以前版本的操作系统没有影响。

8.3 使用字体和文本输出函数

  1. 本节介绍如何使用字体和文本输出函数来绘制普通文本、在同一行上绘制不同字体的文本、旋转文本行、显示字体选择公共对话框、枚举字体等。

8.3.1 使用常用字体绘制文本

  1. 有关详细信息,请参阅使用常用字体绘制文本

8.3.2 创建逻辑字体

  1. 有关详细信息,请参阅创建逻辑字体

8.3.3 枚举已安装的字体

  1. 有关详细信息,请参阅枚举已安装的字体

8.3.4 检查设备的文本功能

  1. 有关详细信息,请参阅检查设备的文本功能

8.3.5 设置文本对齐方式

  1. 有关详细信息,请参阅设置文本对齐方式

8.3.6 在同一行上绘制不同字体的文本

  1. 有关详细信息,请参阅在同一行上绘制不同字体的文本

8.3.7 旋转文本行

  1. 有关详细信息,请参阅旋转文本行

8.3.8 查询字符大纲

  1. 有关详细信息,请参阅查询字符大纲

8.3.9 使用可移植 TrueType 度量

  1. 有关详细信息,请参阅使用可移植 TrueType 度量

8.3.10 使用 PANOSE 数字

  1. 有关详细信息,请参阅使用 PANOSE 数字

8.3.11 指定文本输出字符串的长度

  1. 有关详细信息,请参阅指定文本输出字符串的长度

8.4 字体和文本参考

8.4.1 字体和文本函数

  1. 有关详细信息,请参阅字体和文本函数

8.4.2 字体和文本结构体

  1. 有关详细信息,请参阅字体和文本结构体

8.4.3 字体和文本宏

  1. 有关详细信息,请参阅字体和文本宏

8.4.4 字体和文本消息

  1. 有关详细信息,请参阅字体和文本消息

8.4.5 字体包函数错误消息

  1. 有关详细信息,请参阅字体包函数错误消息

8.5 字体嵌入参考

8.5.1 字体嵌入函数

  1. 有关详细信息,请参阅字体嵌入函数

8.5.2 字体嵌入结构体

  1. 有关详细信息,请参阅字体嵌入结构体

8.5.3 字体嵌入错误消息

  1. 有关详细信息,请参阅字体嵌入错误消息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值