将字体与应用程序一起打包

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

注意

与大多数软件类型一样,字体文件也采用许可模式,而不是出售。 用来控制字体使用的许可证因供应商而异,但一般说来,大多数许可证,包括那些涵盖随应用程序和 Microsoft 提供的字体 Windows 的许可证,都不允许将字体嵌入应用程序中或以其他方式重新发布。 因此,开发人员有责任确保自己具备必要的许可权,可以在应用程序中嵌入相应的字体或者以其他方式重新分布。

字体打包简介

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

OpenType 和 TrueType® 字体包含类型标志 fsType,指示字体的字体嵌入许可权。 但是,这个类型标志仅引用存储在文档中的嵌入字体,而不引用嵌入到应用程序中的字体。 可以通过创建 GlyphTypeface 对象并引用其 EmbeddingRights 属性来检索字体的字体嵌入权。 有关 fsType 标志的详细信息,请参考 OpenType 规范的“OS/2 and Windows Metrics”(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 包含一组 OpenType 字体示例,可以在 WPF 应用程序中使用这些字体。 这些字体是在纯资源库中定义的。 有关详细信息,请参阅示例 OpenType 字体包

字体的使用限制

下表介绍在 WPF 应用程序中对字体进行打包和使用时的一些限制:

  • 字体嵌入权限位:WPF 应用程序不检查或实施任何字体嵌入权限位。 有关详细信息,请参阅 Introduction_to_Packing Fonts 一节。

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

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

  • 自动嵌入字体:在设计时,不支持搜索应用程序对字体的使用情况,而且不支持自动在应用程序的资源中嵌入字体。

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

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

另请参阅