颜色字体支持

本主题介绍颜色字体、它们在 DirectWrite 和 Direct2D (中的支持以及) 的一些其他框架,以及如何在你的应用中使用它们。

什么是颜色字体?

默认情况下,字形具有形状,但没有固有颜色。 DirectWrite和 Direct2D 都具有 DrawGlyphRun 方法,这些方法通过用指定的文本颜色填充字形形状来呈现字形运行。 为方便起见,我们将它称为 单色 字形呈现。 所有字体都有单色字形。 另一方面,颜色字体也具有某些字形的颜色表示形式。 若要以颜色呈现字形,你的应用必须 (使用不同的字形呈现 API,因为我们将讨论) ,而不是调用单色 DrawGlyphRun 方法。

颜色字体也称为多色字体或彩色字体。 它们是一种字体技术,允许字体设计者在每个字形中使用多种颜色。 与在文本呈现系统上实现的临时技术相比,颜色字体在应用和网站中实现多色文本方案的代码更少,操作系统支持更强大。

我们大多数人熟悉的字体 不是 彩色字体。 此类字体仅定义其包含的字形的形状;使用矢量轮廓或单色位图。 在绘制时,文本呈现器使用单一颜色 (正在呈现的应用或文档指定的字体颜色) 填充字形形状。 另一方面,颜色字体除了包含形状信息外, 包含颜色信息。 某些方法允许字体设计人员提供多个调色板,从而赋予颜色字体艺术灵活性。

下面是来自 Segoe UI 表情符号颜色字体的字形。 标志符号以单色呈现在左侧,以颜色呈现在右侧。

显示并排字形,左侧标志符号以单色呈现,右侧为 Segoe U I 表情符号颜色字体。

颜色字体通常包括不支持它们的平台的回退信息,或已禁用颜色功能的方案。 在这些平台上,彩色字体呈现为常规单色字体。

由于颜色字体支持是在字形呈现级别实现的,因此它不会影响文本布局。 无论是使用 IDWriteTextLayout 接口,还是实现自己的文本布局算法,情况都如此。 字符到字形的映射以及这些字形的定位都使用单色字形 ID 及其关联的指标。 文本布局过程的输出是单色字形运行序列。 然后,可以通过在呈现时将这些单色 基本 字形运行转换为颜色字形运行来启用颜色字体支持。

为何使用彩色字体?

从历史上看,设计人员和开发人员使用各种技术来实现多色文本。 例如,网站通常使用光栅图像而不是文本来显示丰富的标头。 此方法可实现艺术灵活性,但光栅图形无法很好地缩放到所有显示大小,并且它们也不提供与真实文本相同的辅助功能。 另一种常见的技术是用不同的字体颜色覆盖多个单色字体:但这通常需要额外的布局代码来管理。

颜色字体提供了一种通过常规字体的所有简单性和功能实现这些视觉效果的方法。 以颜色字体呈现的文本与其他文本相同:可以复制和粘贴,可由辅助功能工具分析,等等。

Windows 支持哪些类型的颜色字体?

OpenType 规范定义了多种在字体中嵌入颜色信息的方法。 从 Windows 10 版本 1607 开始, (周年更新) 、DirectWrite 和 Direct2D (以及基于它们构建的 Windows 框架) 支持所有这些方法:

方法 说明
COLR/CPAL 使用彩色矢量层,其形状的定义方式与单色字形轮廓相同。 Windows 8.1 开始支持。
SVG 使用以可缩放矢量图形 (SVG) 格式创作的矢量图像。 自Windows 10版本 1607 (周年更新) 起,DirectWrite支持完整 SVG 规范的子集。并非所有 SVG 内容都保证以 OpenType SVG 字体呈现。 有关详细信息,请参阅 SVG 支持
CBDT/CBLC 使用嵌入的彩色位图图像。
sbix 使用嵌入的彩色位图图像。

使用颜色字体

从用户的角度来看,颜色字体只是字体。 例如,通常可以采用与单色字体相同的方式从系统安装和卸载它们;它们呈现为常规的可选择文本。

从开发人员的角度来看,颜色字体的使用方式通常与单色字体相同。 在 XAML 和 Microsoft Edge 框架中,可以使用颜色字体设置文本样式,就像使用常规字体一样,默认情况下,文本将以颜色呈现。 但是,如果你的应用直接调用 Direct2D API (或 Win2D API) 来呈现文本,则必须显式请求颜色字体呈现。

将颜色字体与 DirectWrite 和 Direct2D 配合使用

应用可以使用 Direct2D 的更高级别文本绘制方法 (DrawTextDrawTextLayout) ,也可以使用较低级别的技术直接绘制字形运行。 在任一情况下,你的应用都需要特定的代码才能正确处理颜色字形。 默认情况下,Direct2D 的 DrawTextDrawTextLayout API 不呈现颜色标志符号。 这是为了避免在支持颜色字体之前设计的文本呈现应用中出现意外行为更改。

若要选择加入颜色字形呈现,请将 D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT 选项标志传递给绘图方法。 下面的代码示例演示如何调用 Direct2D 的 DrawText 方法以彩色字体呈现字符串:

// If m_textFormat points to a font with color glyphs, then the following
// call will render m_string using the color glyphs available in that font.
// Any monochromatic glyphs will be rendered with m_defaultFillBrush.
m_deviceContext->DrawText(
    m_string->Data(),
    m_string->Length(),
    m_textFormat.Get(),
    m_layoutRect,
    m_defaultFillBrush.Get(),
    D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT
    );

如果你的应用使用较低级别的 API 直接处理字形运行,那么它将在存在彩色字体的情况下继续运行,但是如果没有其他逻辑,它将无法绘制颜色字形。

若要正确处理颜色标志符号,你的应用应:

  1. 将字形运行信息传递给 TranslateColorGlyphRun,以及指示应用准备处理哪种类型的 ( 颜色字形) DWRITE_GLYPH_IMAGE_FORMATS参数。 如果根据字体和请求的DWRITE_GLYPH_IMAGE_FORMATS) (存在任何颜色字形,则DirectWrite会将主要字形运行拆分为各个颜色字形运行,可通过步骤 4 中返回的 IDWriteColorGlyphRunEnumerator1 对象进行访问。
  2. 检查 TranslateColorGlyphRun 返回的 HRESULT 以确定是否检测到任何颜色字形运行。 DWRITE_E_NOCOLOR HRESULT 表示没有适用的颜色字形运行。
  3. 如果 TranslateColorGlyphRun 报告没有通过返回DWRITE_E_NOCOLOR) (的颜色标志符号运行,则整个字形运行被视为单色,并且你的应用应根据需要绘制它 (例如,使用 ID2D1DeviceContext::D rawGlyphRun) 。
  4. 如果 TranslateColorGlyphRun 确实报告了颜色字形运行的存在,则你的应用应忽略主字形运行,而是使用 由 TranslateColorGlyphRun 返回 () 的颜色标志符号运行。 为此,请循环访问返回的 IDWriteColorGlyphRunEnumerator1 对象,检索每个颜色字形运行,并根据需要绘制其字形图像格式 (例如,可以使用 DrawColorBitmapGlyphRunDrawSvgGlyphRun 分别) 绘制颜色位图标志符号和 SVG 字形。

此代码示例演示此过程的一般结构:

// An example code snippet demonstrating how to use TranslateColorGlyphRun 
// to handle different kinds of color glyphs. This code does not make any 
// actual drawing calls. 
HRESULT DrawGlyphRun( 
    FLOAT baselineOriginX, 
    FLOAT baselineOriginY, 
    DWRITE_MEASURING_MODE measuringMode, 
    _In_ DWRITE_GLYPH_RUN const* glyphRun, 
    _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, 
) 
{ 
    // Specify the color glyph formats your app supports. In this example, 
    // the app requests only glyphs defined with PNG or SVG. 
    DWRITE_GLYPH_IMAGE_FORMATS requestedFormats = 
        DWRITE_GLYPH_IMAGE_FORMATS_PNG | DWRITE_GLYPH_IMAGE_FORMATS_SVG; 

    ComPtr<IDWriteColorGlyphRunEnumerator1> glyphRunEnumerator; 
    HRESULT hr = m_dwriteFactory->TranslateColorGlyphRun( 
        D2D1::Point2F(baselineOriginX, baselineOriginY), 
        glyphRun, 
        glyphRunDescription, 
        requestedFormats, // The glyph formats supported by this renderer.
        measuringMode, 
        nullptr, 
        0, 
        &glyphRunEnumerator // On return, may contain color glyph runs.
        ); 

    if (hr == DWRITE_E_NOCOLOR) 
    { 
        // The glyph run has no color glyphs. Draw it as a monochrome glyph 
        // run, for example using the DrawGlyphRun method on a Direct2D 
        // device context. 
    } 
    else 
    { 
        // The glyph run has one or more color glyphs. 
        DX::ThrowIfFailed(hr); 

        // Iterate through the color glyph runs, and draw them. 
        for (;;) 
        { 
            BOOL haveRun; 
            DX::ThrowIfFailed(glyphRunEnumerator->MoveNext(&haveRun)); 
            if (!haveRun) 
            { 
                break; 
            } 

            // Retrieve the color glyph run. 
            DWRITE_COLOR_GLYPH_RUN1 const* colorRun; 
            DX::ThrowIfFailed(glyphRunEnumerator->GetCurrentRun(&colorRun)); 

            // Draw the color glyph run depending on its format. 
            switch (colorRun->glyphImageFormat) 
            { 
            case DWRITE_GLYPH_IMAGE_FORMATS_PNG: 
                // Draw the PNG glyph, for example with 
                // ID2D1DeviceContext4::DrawColorBitmapGlyphRun. 
                break; 

            case DWRITE_GLYPH_IMAGE_FORMATS_SVG: 
                // Draw the SVG glyph, for example with 
                // ID2D1DeviceContext4::DrawSvgGlyphRun. 
                break; 

                // ...etc. 
            } 
        } 
    } 

    return hr; 
} 

在 XAML 应用中使用颜色字体

默认情况下,XAML 平台的文本元素(如 TextBlockTextBoxRichEditBox字形FontIcon)支持颜色字体。 只需使用彩色字体设置文本样式,任何颜色字形都将以颜色呈现。

以下语法演示了使用与应用一起打包的颜色字体设置 TextBlock 样式的一种方法。 同样的技术也适用于常规字体。

<TextBlock FontFamily="Assets/TMyColorFont.otf#MyFontFamilyName">Here's some text.</TextBlock>

如果希望 XAML 文本元素 从不 呈现多色文本,则将其 IsColorFontEnabledProperty 属性设置为 false

提示

上述链接指向这些 XAML 控件的 WinUI 3 版本。 可以在 Windows.UI.Xaml.Controls 命名空间中找到通用 Windows 平台 (UWP) 等效项。

在 Microsoft Edge 中使用颜色字体

默认情况下,颜色字体在 Microsoft Edge 上运行的网站和 Web 应用中呈现,包括 XAML WebView2 控件。 只需使用 HTML 和 CSS 使用颜色字体设置文本样式,任何颜色字形都将以颜色呈现。

将彩色字体与 Win2D 配合使用

与 Direct2D 类似,Win2D 的文本绘制 API 默认不呈现颜色字形。 若要选择加入颜色字形呈现,请在应用传递给文本绘制方法的文本格式对象中设置 EnableColorFont 选项标志。 下面的代码示例演示如何使用 Win2D 以彩色字体呈现字符串:

// The text format that will be used to draw the text. (Declared elsewhere 
// and initialized elsewhere by the app to point to a color font.) 
CanvasTextFormat m_textFormat; 

// Set the EnableColorFont option. 
m_textFormat.Options = CanvasDrawTextOptions.EnableColorFont; 

// If m_textFormat points to a font with color glyphs, then the following
// call will render m_string using the color glyphs available in that font.
// Any monochromatic glyphs will be rendered with m_color.
args.DrawingSession.DrawText(
    m_string,
    m_point,
    m_color,
    m_textFormat
    );