DWriteCore 概觀
DWriteCore 是 Windows App SDK 實作 DirectWrite (DirectWrite 是適用於高品質文字轉譯的 DirectX API、與解析度無關的大綱字型,以及完整的 Unicode 文字和版面配置支援)。 DWriteCore 是一種 DirectWrite 形式,可以在從 Windows 10 版本 1809 (10.0,組建 17763)開始的各種 Windows 版本中運行。 DWriteCore 會實作與 DirectWrite 相同的 API,並新增一些內容,如本主題所述。
此簡介主題描述 DWriteCore 是什麼,並示範如何將它安裝到您的開發環境和程式。
對於已經使用 DirectWrite 的應用程式,切換至 DWriteCore 需要最少的變更:
- 新增 Windows App SDK 套件的參考。
- 包含
dwrite_core.h
,而不是dwrite_3.h
。 - 連結
DWriteCore.lib
,而不是DWrite.lib
。 - 呼叫 DWriteCoreCreateFactory,而不是 DWriteCreateFactory。
在回報中,應用程式會取得 Windows App SDK 的優點,也就是不論客戶執行哪個 Windows 版本,都能存取最新的 API 和功能。
提示
如需使用中開發中 DirectX 元件的描述和連結,請參閱部落格文章 DirectX 登陸頁面。
DWriteCore 的價值主張
DirectWrite 本身支援豐富的功能陣列,使其成為大多數 app 在 Windows 上選擇的字型轉譯工具,無論是透過直接呼叫,還是透過 Direct2D。 DirectWrite 包含與裝置無關的文字版面配置系統、高品質的子圖元 Microsoft ClearType 文字轉譯、硬體加速文字、多重格式文字、進階 OpenType® 印刷樣式功能、廣泛的語言支援,以及 GDI兼容的版面配置和轉譯。 DirectWrite 自 Windows Vista SP2 以來一直可供使用,多年來已發展為包含更進階的功能,例如可變字型,可讓您將樣式、粗細和其他屬性套用至只有一個字型資源的字型。
不過,由於 DirectWrite 的壽命很長,開發中的進展往往使舊版 Windows 落後。 此外,DirectWrite 作為頂級文字轉譯技術的狀態僅限於 Windows,讓跨平臺應用程式能夠撰寫自己的文字轉譯堆疊,或依賴第三方解決方案。
DWriteCore 藉移除系統中的該程式庫,並以所有可能支援的端點為目標,來解決版本功能孤立化和跨平臺相容性的基本問題。 為此,我們已將 DWriteCore 整合到 Windows App SDK。
在 Windows App SDK 中,DWriteCore 作為開發人員的您提供的主要價值,就是它提供許多(並最終是所有)DirectWrite 功能的存取權。 DWriteCore 的所有功能都會在所有下層版本上運作相同,而不會有任何關於哪些功能在哪些版本上可能運作的差異。
DWriteCore 示範應用程式 — DWriteCoreGallery
DWriteCore 是透過 DWriteCoreGallery 範例應用程式來示範,現在可供您下載並研究。
開始使用 DWriteCore
DWriteCore 是 Windows App SDK的一部分。 本節說明如何設定您的開發環境,以使用 DWriteCore 進行程序設計。
安裝適用於 Windows App SDK 的工具
請參閱 Windows App SDK安裝工具。
建立新專案
在 Visual Studio 中,從 空白應用程式、已封裝 (Desktop 中的 WinUI 3) 項目範本建立新專案。 您可以選擇語言來找到該專案範本:C++;platform:Windows App SDK;項目類型:Desktop。
如需詳細資訊,請參閱 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 App SDK的一部分。 您身為開發人員所需的基本工具,其中包括用來取用 DWriteCore 的功能如下。
- 字型列舉。
- 字型 API。
- 塑造。
- 低階轉譯 API。 這是目前階段的一部分,DWriteCore 不會與 Direct2D互作,但您可以使用 IDWriteGlyphRunAnalysis 和 IDWriteBitmapRenderTarget。
- 基本文字排版功能。
- 文字轉譯 API。
- 點陣圖渲染目標。
- 色彩字型。
- 其他優化(字型快取清除、記憶體內部字型載入器等等)。
- 支援底線—請參閱 IDWriteTextLayout::GetUnderline 和 IDWriteTextLayout::SetUnderline。
- 支援刪除線-請參閱 IDWriteTextLayout::GetStrikethrough 和 IDWriteTextLayout::SetStrikethrough。
- 透過 IDWriteTextLayout支援垂直文字 —請參閱 垂直文字。
- 已實作 IDWriteTextAnalyzer 和 IDWriteTextAnalyzer1 介面的所有方法。
橫幅功能是色彩字型。 色彩字型可讓您以更複雜的色彩功能呈現字型,而不只是簡單的單一色彩。 例如,色彩字型是可轉譯 emoji 和工具列圖示字型的功能(例如 Office 會使用後者)。 色彩字型首次在 Windows 8.1 中引進,但此功能在 Windows 10 版本 1607(年度更新版)中大幅擴充。
字型快取和記憶體內的字型載入器清理工作,可以加快字型載入速度並提升記憶體效率。
透過這些功能,您可以立即開始運用 DirectWrite 的一些新式核心功能,例如可變字型。 可變字體是 DirectWrite 客戶最重要的功能之一。
我們邀請您成為 DirectWrite 開發人員
DWriteCore 以及其他 Windows App SDK 元件,將會以對開發人員的意見反應開放進行開發。 我們誠摯邀請您開始探索 DWriteCore,並在 Windows 應用程式 SDK GitHub 存放庫中分享您的見解或提出功能開發的要求。
使用 DWriteCore 進行程序設計
就像使用 DirectWrite一樣,您可以透過其 COM-light API 使用 DWriteCore,透過 IDWriteFactory 介面進行程式設計。
若要使用 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
DWriteCore API 介面與 DirectWrite 大致相同。 目前,只有少數新的 API 在 DWriteCore 中。
建立工廠物件
DWriteCoreCreateFactory free 函式會建立處理站物件,以供後續建立個別 DWriteCore 物件。
DWriteCoreCreateFactory 的運作方式與 DirectWrite 系統版本導出的 DWriteCreateFactory 函式相同。 DWriteCore 函式有不同的名稱,以避免模棱兩可。
建立受限制的 Factory 物件
DWRITE_FACTORY_TYPE 列舉具有新的常數,DWRITE_FACTORY_TYPE_ISOLATED2,表示受限制的工廠。 受限制的工廠比隔離的工廠限制更嚴格。 它不會以任何方式與跨進程或持續性字型快取互動。 此外,從此處理站傳回的系統字型集合只包含已知的字型。 以下是當您呼叫 DWriteCoreCreateFactory free 函式時,如何使用 DWRITE_FACTORY_TYPE_ISOLATED2 來建立受限制的 Factory 物件。
// 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 記憶體 DC,並將 GDI 裝置無關位圖(DIB)選入其中。 IDWriteBitmapRenderTarget::DrawGlyphRun 將字形渲染到 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,因為沒有 GDI的 HDC。
最後,還有其他一些 Windows API 通常會與 DirectWrite 一起使用(Direct2D 是值得注意的範例)。 不過,目前 Direct2D 和 DWriteCore 不會互作。 例如,如果您使用 DWriteCore 建立 IDWriteTextLayout,並將它傳遞至 D2D1RenderTarget::D rawTextLayout,則該呼叫將會失敗。