使用应用程序打包字体

本主题概述如何使用 Windows Presentation Foundation (WPF) 应用程序打包字体。

注释

与大多数类型的软件一样,字体文件是许可的,而不是出售的。 管理字体使用的许可证因供应商而异,但一般情况下,大多数许可证(包括涵盖应用程序和 Windows 随附的字体Microsoft的许可证)不允许将字体嵌入到应用程序内,或者重新分发。 因此,作为开发人员,你需要负责确保你拥有在应用程序内嵌入的任何字体所需的许可证权限,或者重新分发。

打包字体简介

可以轻松地将字体打包为 WPF 应用程序中的资源,以显示用户界面文本和其他类型的基于文本的内容。 字体可以独立于应用程序的程序集文件,也可以嵌入到这些文件中。 还可以创建仅限资源的字体库,应用程序可以引用该库。

OpenType 和 TrueType® 字体包含一个类型标志 fsType,用于指示字体的嵌入许可权限。 但是,此类型标志仅引用存储在文档中的嵌入字体-它不引用应用程序中嵌入的字体。 可以通过创建 GlyphTypeface 对象并引用其 EmbeddingRights 属性来检索字体的字体嵌入权限。 有关 fsType 标志的详细信息,请参阅 OpenType 规范 的“OS/2 和 Windows 指标”部分。

Microsoft版式网站包含可帮助查找特定字体供应商或查找用于自定义工作的字体供应商的联系信息。

将字体添加为内容项

可以将字体作为独立于应用程序的程序集文件的项目内容项添加到应用程序。 这意味着内容项不会作为资源嵌入到程序集。 以下项目文件示例演示如何定义内容项。

<Project DefaultTargets="Build"
                xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Other project build settings ... -->

  <ItemGroup>
    <Content Include="Peric.ttf" />
    <Content Include="Pericl.ttf" />
  </ItemGroup>
</Project>

为了确保应用程序可以在运行时使用字体,必须在应用程序的部署目录中访问字体。 应用程序 <CopyToOutputDirectory> 项目文件中的元素允许你在生成过程中自动将字体复制到应用程序部署目录。 以下项目文件示例演示如何将字体复制到部署目录。

<ItemGroup>
  <Content Include="Peric.ttf">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
  <Content Include="Pericl.ttf">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
</ItemGroup>

下面的代码示例演示如何将应用程序的字体作为内容项引用,所引用的内容项必须与应用程序的程序集文件位于同一目录中。

<TextBlock FontFamily="./#Pericles Light">
  Aegean Sea
</TextBlock>

将字体添加为资源项

可以将字体作为嵌入到应用程序的程序集文件中的项目资源项添加到应用程序。 对资源使用单独的子目录有助于组织应用程序的项目文件。 以下项目文件示例演示如何将字体定义为单独的子目录中的资源项。

<Project DefaultTargets="Build"
                xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Other project build settings ... -->

  <ItemGroup>
    <Resource Include="resources\Peric.ttf" />
    <Resource Include="resources\Pericl.ttf" />
  </ItemGroup>
</Project>

注释

将字体作为资源添加到应用程序时,请确保设置 <Resource> 元素,而不是 <EmbeddedResource> 应用程序项目文件中的元素。 <EmbeddedResource> 元素不支持生成操作。

以下标记示例演示如何引用应用程序的字体资源。

<TextBlock FontFamily="./resources/#Pericles Light">
  Aegean Sea
</TextBlock>

从代码引用字体资源项

若要从代码引用字体资源项,必须提供由两部分构成的字体资源引用:基本统一资源标识符(URI):和字体位置参考。 这些值用作方法的参数 FontFamily 。 下面的代码示例演示如何在名为 resources 的项目子目录中引用应用程序的字体资源。

// The font resource reference includes the base URI reference (application directory level),
// and a relative URI reference.
myTextBlock.FontFamily = new FontFamily(new Uri("pack://application:,,,/"), "./resources/#Pericles Light");
' The font resource reference includes the base URI reference (application directory level),
' and a relative URI reference.
myTextBlock.FontFamily = New FontFamily(New Uri("pack://application:,,,/"), "./resources/#Pericles Light")

基本统一资源标识符(URI)可以包括字体资源所在的应用程序子目录。 在这种情况下,字体位置引用不需要指定目录,但必须包含前导“”./,这表示字体资源位于基本统一资源标识符(URI)指定的同一目录中。 下面的代码示例演示了引用字体资源项的替代方法,它等效于前面的代码示例。

// The base URI reference can include an application subdirectory.
myTextBlock.FontFamily = new FontFamily(new Uri("pack://application:,,,/resources/"), "./#Pericles Light");
' The base URI reference can include an application subdirectory.
myTextBlock.FontFamily = New FontFamily(New Uri("pack://application:,,,/resources/"), "./#Pericles Light")

引用同一应用程序子目录中的字体

可以将应用程序内容和资源文件放在应用程序项目的同一用户定义的子目录中。 以下项目文件示例显示了在同一子目录中定义的内容页和字体资源。

<ItemGroup>
  <Page Include="pages\HomePage.xaml" />
</ItemGroup>
<ItemGroup>
  <Resource Include="pages\Peric.ttf" />
  <Resource Include="pages\Pericl.ttf" />
</ItemGroup>

由于应用程序内容和字体位于同一个子目录中,因此字体引用相对于应用程序内容。 以下示例演示如何在字体与应用程序位于同一目录中时引用应用程序的字体资源。

<TextBlock FontFamily="./#Pericles Light">
  Aegean Sea
</TextBlock>
// The font resource reference includes the base Uri (application directory level),
// and the file resource ___location, which is relative to the base Uri.
myTextBlock.FontFamily = new FontFamily(new Uri("pack://application:,,,/"), "/pages/#Pericles Light");
' The font resource reference includes the base Uri (application directory level),
' and the file resource ___location, which is relative to the base Uri.
myTextBlock.FontFamily = New FontFamily(New Uri("pack://application:,,,/"), "/pages/#Pericles Light")

列出应用程序中的字体

若要将字体枚举为应用程序中的资源项,请使用 GetFontFamiliesGetTypefaces 方法。 以下示例演示如何使用 GetFontFamilies 该方法从应用程序字体位置返回对象的集合 FontFamily 。 在这种情况下,应用程序包含名为“resources”的子目录。

foreach (FontFamily fontFamily in Fonts.GetFontFamilies(new Uri("pack://application:,,,/"), "./resources/"))
{
    // Perform action.
}
For Each fontFamily As FontFamily In Fonts.GetFontFamilies(New Uri("pack://application:,,,/"), "./resources/")
    ' Perform action.
Next fontFamily

以下示例演示如何使用 GetTypefaces 该方法从应用程序字体位置返回对象的集合 Typeface 。 在这种情况下,应用程序包含名为“resources”的子目录。

foreach (Typeface typeface in Fonts.GetTypefaces(new Uri("pack://application:,,,/"), "./resources/"))
{
    // Perform action.
}
For Each typeface As Typeface In Fonts.GetTypefaces(New Uri("pack://application:,,,/"), "./resources/")
    ' Perform action.
Next typeface

创建字体资源库

可以创建一个仅包含字体的资源库,并且这种类型的库项目不包含任何代码。 创建仅资源库是将资源与使用这些库的应用程序代码分离的常见技术。 这还允许将库程序集包含在多个应用程序项目中。 以下项目文件示例显示了一个仅包含资源的库项目的关键部分。

<PropertyGroup>
  <AssemblyName>FontLibrary</AssemblyName>
  <OutputType>library</OutputType>
  ...
</PropertyGroup>
...
<ItemGroup>
  <Resource Include="Kooten.ttf" />
  <Resource Include="Pesca.ttf" />
</ItemGroup

引用资源库中的字体

若要从应用程序引用资源库中的字体,必须以库程序集的名称为字体引用前缀。 在这种情况下,字体资源程序集为“FontLibrary”。 若要将程序集名称与程序集内的引用分开,请使用“;”字符。 添加“Component”关键字后跟对字体名称的引用完成对字体库资源的完整引用。 下面的代码示例演示如何引用资源库程序集中的字体。

<Run FontFamily="/FontLibrary;Component/#Kootenay" FontSize="36">
  ABCDEFGHIJKLMNOPQRSTUVWXYZ
</Run>

注释

此 SDK 包含一组可用于 WPF 应用程序的示例 OpenType 字体。 字体在只包含资源的库中定义。 有关详细信息,请参阅 示例 OpenType 字体包

字体使用限制

以下列表描述了在 WPF 应用程序中打包和使用字体的若干限制:

  • 字体嵌入权限位: WPF 应用程序不会检查或强制实施任何字体嵌入权限位。 有关详细信息,请参阅打包字体简介部分。

  • 源字体网站: WPF 应用程序不允许对 http 或 ftp 统一资源标识符(URI)的字体引用。

  • 使用 pack: 表示法的绝对 URI: WPF 应用程序不允许以“pack:”作为对字体的绝对统一资源标识符 (URI) 引用的一部分来以编程方式创建 FontFamily 对象。 例如, "pack://application:,,,/resources/#Pericles Light" 字体引用无效。

  • 自动字体嵌入: 在设计期间,不支持搜索应用程序的字体使用,并自动将字体嵌入应用程序资源。

  • 字体子集: WPF 应用程序不支持为非固定文档创建字体子集。

  • 如果引用不正确,应用程序会回退到使用可用字体。

另请参阅