DWriteCore 概述

DWriteCore 是 DirectWriteWindows 应用 SDK 实现(DirectWrite 是用于高质量文本呈现、与分辨率无关的大纲字体以及完整的 Unicode 文本和布局支持的 DirectX API)。 DWriteCore 是一种DirectWrite形式,在 Windows 版本(Windows 10 版本 1809 (10.0)上运行;内部版本 17763) 。 DWriteCore 实现与 DirectWrite 相同的 API,并添加一些内容,如本主题中所述。

本介绍性主题介绍什么是 DWriteCore,并演示如何将其安装到开发环境中并使用它进行编程。

对于已使用 DirectWrite 的应用,切换到 DWriteCore 所需的更改最少:

作为回报,应用会获得Windows 应用 SDK的好处,即,无论客户运行的是哪个版本的 Windows,都可以访问最新的 API 和功能。

提示

有关活动开发中的 DirectX 组件的说明和链接,请参阅博客文章 DirectX 登陆页面

DWriteCore 的价值主张

DirectWrite本身支持丰富的功能,使它成为大多数应用在 Windows 上选择的字体呈现工具-无论是通过直接调用还是通过 Direct2D。 DirectWrite包括与设备无关的文本布局系统、高质量的子像素 Microsoft ClearType 文本呈现、硬件加速文本、多格式文本、高级 OpenType® 版式功能、宽语言支持以及 GDI 兼容的布局和呈现。 DirectWrite自 Windows Vista SP2 以来一直可用,多年来,它不断演变为包含更高级的功能,例如可变字体,这使你能够将样式、粗细和其他属性应用于只有一个字体资源的字体。

但是,由于DirectWrite的寿命很长,开发的进步往往使旧版本的 Windows 落后。 此外,DirectWrite作为顶级文本呈现技术的地位仅限于 Windows,使跨平台应用程序可以编写自己的文本呈现堆栈,或依赖于第三方解决方案。

DWriteCore 通过从系统中删除库并面向所有可能支持的终结点,解决了版本功能孤立和跨平台兼容性的基本问题。 为此,我们已将 DWriteCore 集成到Windows 应用 SDK。

作为开发人员,DWriteCore 在Windows 应用 SDK中提供的主要价值是,它提供对许多 (并最终所有) DirectWrite 功能的访问权限。 DWriteCore 的所有功能在所有下层版本上都相同,在哪些功能可用于哪些版本方面没有任何差异。

DWriteCore 演示应用 - DWriteCoreGallery

DWriteCoreGallery 示例应用演示了 DWriteCore ,现在可供下载和学习。

DWriteCore 入门

DWriteCore 是Windows 应用 SDK的一部分。 本部分介绍如何设置使用 DWriteCore 进行编程的开发环境。

安装适用于 Windows 应用 SDK 的工具

请参阅安装适用于 Windows 应用 SDK 的工具

创建新项目

在 Visual Studio 中,从“桌面) 项目模板 中的空白应用打包 (WinUI 3 创建新项目。 可以通过选择语言来查找该项目模板:C++;平台:Windows 应用 SDK;项目类型:桌面

有关详细信息,请参阅 WinUI 3 的项目模板

安装 Microsoft.ProjectReunion.DWrite NuGet 包

在 Visual Studio 中,单击“ 项目管理>NuGet 包...”>浏览,在搜索框中键入或粘贴 Microsoft.ProjectReunion.DWrite ,在搜索结果中选择该项,然后单击“ 安装 ”为该项目安装包。

或者,从 DWriteCoreGallery 示例应用开始

或者,可以从 DWriteCoreGallery 示例应用项目开始,使用 DWriteCore 进行编程,并基于该项目进行开发。 然后,你可以随意从该示例项目中删除任何现有的源代码 (或文件) ,并将任何新的源代码 (或) 文件添加到项目中。

在项目中使用 DWriteCore

有关使用 DWriteCore 编程的详细信息,请参阅本主题后面的 使用 DWriteCore 编程 部分。

DWriteCore 的发布阶段

将DirectWrite移植到 DWriteCore 是一个足够大的项目,可以跨多个 Windows 发布周期。 该项目分为多个阶段,每个阶段对应于在发布中交付的一大块功能。

DWriteCore 当前版本中的功能

DWriteCore 是Windows 应用 SDK的一部分。 它包含开发人员需要使用 DWriteCore 的基本工具,包括以下功能。

横幅功能是颜色字体。 通过颜色字体,可以使用比简单单一颜色更复杂的颜色功能来呈现字体。 例如,颜色字体是能够呈现表情符号和工具栏图标字体的功能, (后者由 Office 使用,例如) 。 颜色字体在 Windows 8.1 中首次引入,但该功能在Windows 10版本 1607 (周年更新) 中得到了大量扩展。

通过清理字体缓存和内存中字体加载程序,可以更快地加载字体并改进内存。

借助这些功能,你可以立即开始利用DirectWrite的一些新式核心功能,例如可变字体。 可变字体是DirectWrite客户最重要的功能之一。

我们邀请你作为DirectWrite开发人员

DWriteCore 以及其他Windows 应用 SDK组件将在开发时向开发人员反馈开放。 我们邀请你开始探索 DWriteCore,并在 Windows 应用 SDK GitHub 存储库中提供有关功能开发的见解或请求。

使用 DWriteCore 编程

DirectWrite 一样,可以通过 DWriteCore 的 COM-light API 通过 IDWriteFactory 接口对 DWriteCore 进行编程。

若要使用 DWriteCore,必须包含 dwrite_core.h 头文件。

// pch.h
...
// DWriteCore header file.
#include <dwrite_core.h>

dwrite_core.h 文件首先定义 令牌DWRITE_CORE,然后包含 dwrite_3.h 头文件。 DWRITE_CORE令牌非常重要,因为它会指示所有后续包含的标头,使所有DirectWrite API 都可供你使用。 项目包含 dwrite_core.h后,可以继续编写代码、生成和运行。

DWriteCore 的新 API 或不同 API

DWriteCore API 图面与用于DirectWrite大致相同。 但目前只有少量的新 API 仅位于 DWriteCore 中。

创建工厂对象

DWriteCoreCreateFactory free 函数创建一个工厂对象,该对象用于后续创建各个 DWriteCore 对象。

DWriteCoreCreateFactory 在功能上与 DirectWrite 的系统版本导出的 DWriteCreateFactory 函数相同。 DWriteCore 函数具有不同的名称,以避免歧义。

创建受限工厂对象

DWRITE_FACTORY_TYPE枚举具有一个新的常量-DWRITE_FACTORY_TYPE_ISOLATED2,指示受限工厂。 受限工厂比隔离工厂更被锁定。 它不会以任何方式与跨进程或永久性字体缓存交互。 此外,从此工厂返回的系统字体集合仅包含已知字体。 下面介绍如何在调用 DWriteCoreCreateFactory 免费函数时使用 DWRITE_FACTORY_TYPE_ISOLATED2 创建受限工厂对象。

// Create a factory that doesn't interact with any cross-process nor
// persistent cache state.
winrt::com_ptr<::IDWriteFactory7> spFactory;
winrt::check_hresult(
  ::DWriteCoreCreateFactory(
    DWRITE_FACTORY_TYPE_ISOLATED2,
    __uuidof(spFactory),
    reinterpret_cast<IUnknown**>(spFactory.put())
  )
);

如果将DWRITE_FACTORY_TYPE_ISOLATED2传递给不支持它的较旧版本的 DirectWrite,则 DWriteCreateFactory 将返回E_INVALIDARG

将字形绘制到系统内存位图

DirectWrite具有位图呈现目标接口,该接口支持将字形呈现到系统内存中的位图。 但是,目前访问基础像素数据的唯一方法是通过 GDI,因此 API 不可跨平台使用。 通过添加方法来检索像素数据,可以轻松解决此问题。

因此,DWriteCore 引入了 IDWriteBitmapRenderTarget2 接口及其方法 IDWriteBitmapRenderTarget2::GetBitmapData。 该方法采用指向) 类型 DWRITE_BITMAP_DATA_BGRA32(新结构)的 (指针的参数。

应用程序通过调用 IDWriteGdiInterop::CreateBitmapRenderTarget 创建位图呈现目标。 在 Windows 上,位图呈现目标使用与 GDI 设备无关的位图封装 GDI 内存 DC, (DIB) 选择到其中。 IDWriteBitmapRenderTarget::D rawGlyphRun 将字形呈现到 DIB。 DirectWrite呈现字形本身,而无需通过 GDI。 然后,应用程序可以从位图呈现目标获取 HDC ,并使用 BitBlt 将像素复制到窗口 HDC

在非 Windows 平台上,应用程序仍然可以创建位图呈现目标,但它只是封装没有 HDC 和 DIB 的系统内存数组。 如果没有 HDC,应用程序需要有另一种方法来获取位图像素,以便可以复制或以其他方式使用它们。 即使在 Windows 上,获取实际像素数据有时也很有用,我们在下面的代码示例中演示了执行此操作的当前方法。

// pch.h
#pragma once

#include <windows.h>
#include <Unknwn.h>
#include <winrt/Windows.Foundation.h>

// WinMain.cpp
#include "pch.h"
#include <dwrite_core.h>
#pragma comment(lib, "Gdi32")

class TextRenderer
{
    DWRITE_BITMAP_DATA_BGRA32 m_targetBitmapData;

public:
    void InitializeBitmapData(winrt::com_ptr<IDWriteBitmapRenderTarget> const& renderTarget)
    {
        // Query the bitmap render target for the new interface. 
        winrt::com_ptr<IDWriteBitmapRenderTarget2> renderTarget2;
        renderTarget2 = renderTarget.try_as<IDWriteBitmapRenderTarget2>();

        if (renderTarget2)
        {
            // IDWriteBitmapRenderTarget2 exists, so we can get the bitmap the easy way. 
            winrt::check_hresult(renderTarget2->GetBitmapData(OUT & m_targetBitmapData));
        }
        else
        {
            // We're using an older version that doesn't implement IDWriteBitmapRenderTarget2, 
            // so we have to get the bitmap by going through GDI. First get the bitmap handle. 
            HDC hdc = renderTarget->GetMemoryDC();
            winrt::handle dibHandle{ GetCurrentObject(hdc, OBJ_BITMAP) };
            winrt::check_bool(bool{ dibHandle });

            // Call a GDI function to fill in the DIBSECTION structure for the bitmap. 
            DIBSECTION dib;
            winrt::check_bool(GetObject(dibHandle.get(), sizeof(dib), &dib));

            m_targetBitmapData.width = dib.dsBm.bmWidth;
            m_targetBitmapData.height = dib.dsBm.bmHeight;
            m_targetBitmapData.pixels = static_cast<uint32_t*>(dib.dsBm.bmBits);
        }
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
    TextRenderer textRenderer;
    winrt::com_ptr<IDWriteBitmapRenderTarget> renderTarget{ /* ... */ };
    textRenderer.InitializeBitmapData(renderTarget);
}

DWriteCore 与 DirectWrite 之间的其他 API 差异

有一些 API 要么只是存根,要么在非 Windows 平台上的行为略有不同。 例如, IDWriteGdiInterop::CreateFontFaceFromHdc 在非 Windows 平台上返回 E_NOTIMPL ,因为 HDC 没有 GDI

最后,还有一些其他 Windows API 通常与 DirectWrite (Direct2D 一起使用,这是一个值得注意的示例) 。 但是,目前 Direct2D 和 DWriteCore 无法互操作。 例如,如果使用 DWriteCore 创建 IDWriteTextLayout ,并将其传递给 D2D1RenderTarget::D rawTextLayout,则该调用将失败。