颜色字体支持

本主题介绍颜色字体、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 支持
CBT/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,以确定是否检测到任何颜色标志符号运行。 HRESULTDWRITE_E_NOCOLOR 指示没有适用的颜色标志符号运行。
  3. 如果 TranslateColorGlyphRun 不报告颜色字形运行(通过返回 DWRITE_E_NOCOLOR),则整个字形运行将被视为单色,并且你的应用应根据需要绘制它(例如,使用 ID2D1DeviceContext::D rawGlyphRun)。
  4. 如果 TranslateColorGlyphRun 确实报告了颜色标志符号运行的状态,则应用应忽略主字形运行,而是使用 translateColorGlyphRun 返回的颜色字形 run(s)。 为此,请循环访问返回 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
    );