使用 Direct2D 和 DirectWrite 轉譯文字

不同於其他 API,例如 GDI、GDI+ 或 WPF,Direct2D 會與另一個 API DirectWrite 互操作,以操作和轉譯文字。 本主題描述這些個別元件的優點和互操作。

本主題包含下列各節。

Direct2D 啟用累加採用

將應用程式從一個圖形 API 移至另一個圖形 API 可能會因為各種原因而難以或不是您想要的。 這可能是因為您必須支援仍然採用較舊介面的外掛程式,因為應用程式本身太大而無法移植到一個版本中的新 API,或因為較新的 API 的某些部分是可取的,但較舊的 API 對於應用程式的其他部分而言運作良好。

因為 Direct2DDirectWrite 會實作為個別元件,所以您可以升級整個 2D 圖形系統,或只升級其文字部分。 例如,您可以更新應用程式以使用 DirectWrite 進行文字,但仍使用 GDI 或 GDI+ 進行轉譯。

文字服務與文字轉譯

隨著應用程式的發展,其文字處理需求變得越來越複雜。 一開始,文字通常會受限於靜態配置 UI,而且文字會在定義完善的方塊中轉譯,例如按鈕。 隨著應用程式開始以越來越多的語言提供,這種方法變得更加難以維持,因為翻譯文字的寬度和高度在語言之間可能會有很大的差異。 為了適應,應用程式開始動態配置其UI,以根據文字的實際轉譯大小,而不是相反的方式。

為了協助應用程式完成這項工作,DirectWrite 會提供IDWriteTextLayout 介面。 此 API 可讓應用程式指定具有複雜特性的文字片段,例如不同的字型和字型大小、底線、刪除線、雙向文字、效果、省略號,甚至內嵌的非字元字元(例如位圖圖圖或圖示)。 然後,應用程式可以變更文字的各種特性,因為它反覆判斷其UI配置。 下圖所示的 DirectWrite Hello World 範例,以及教學課程:開始使用 DirectWrite 主題會顯示許多這些效果。

“hello world” 範例的螢幕快照。

版面配置可以根據圖像的寬度(如 WPF 所示)來放置圖像,也可以將圖像貼齊到最接近的圖元位置(如 GDI 所示)。

除了取得文字量測之外,應用程式還可以點擊測試文字的各個部分。 例如,它可能想要知道已按下文字中的超連結。 (如需點擊測試的詳細資訊,請參閱 如何在文字版面配置 主題上執行點擊測試。

文字配置介面會與應用程式所使用的轉譯 API 分離,如下圖所示:

文字版面配置和圖形 API 圖表。

因為 DirectWrite 提供轉譯介面 (IDWriteTextRenderer), 應用程式可以使用您想要的任何圖形 API 來實作轉譯文字,因此可能會進行此分隔。 在轉譯文字配置時,DirectWrite 會呼叫實 作 IDWriteTextRenderer::D rawGlyphRun 回呼方法的應用程式。 此方法負責執行繪圖作業或一起傳遞。

對於繪圖圖像,Direct2D 會提供 ID2D1RenderTarget::D rawGlyphRun 來繪製到 Direct2D 表面,而 DirectWrite 提供 IDWriteBitmapRenderTarget::D rawGlyphRun,以便使用 GDI 將繪圖傳送到視窗。 方便使用,Direct2D 和 DirectWrite 中的 DrawGlyphRun 都有與應用程式在 IDWriteTextRenderer 上實作的 DrawGlyphRun 方法完全相同的參數

在類似的分隔之後,文字特定功能(例如字型列舉和管理、圖像分析等等)是由 DirectWrite 處理, 而不是 Direct2D。 Direct2D 會直接接受 DirectWrite 物件。 為了協助現有的 GDI 應用程式利用 DirectWrite,它會提供 IDWriteGdiInterop 方法介面,並提供方法來執行下列動作:

字元與文字

文字是一組 Unicode 字碼點(字元),具有各種文體修飾詞(字型、粗細、底線、刪除線等等),以矩形配置。 相反地,字元是特定字型檔案中的特定索引。 圖像會定義一組可轉譯的曲線,但沒有任何文字意義。 字元與字元之間可能有多對多對應。 來自相同字型臉部的字元序列,且在基準上循序排列的字元序列稱為 GlyphRun。 DirectWrite 和 Direct2D 都會呼叫其最精確的圖像轉譯 API DrawGlyphRun,而且其簽章非常類似。 以下是來自 Direct2D 中的 ID2D1RenderTarget

STDMETHOD_(void, DrawGlyphRun)(
        D2D1_POINT_2F baselineOrigin,
        __in CONST DWRITE_GLYPH_RUN *glyphRun,
        __in ID2D1Brush *foregroundBrush,
        DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL 
        ) PURE;

這個方法來自 DirectWrite 中的 IDWriteBitmapRenderTarget

STDMETHOD(DrawGlyphRun)(
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        IDWriteRenderingParams* renderingParams,
        COLORREF textColor,
        __out_opt RECT* blackBoxRect = NULL
        ) PURE;

DirectWrite 版本會保留基準原點、測量模式和字元執行參數,並包含其他參數。

DirectWrite 也可讓您藉由實 作 IDWriteTextRenderer 介面來使用自定義轉譯器 做為字元。 此介面也有 DrawGlyphRun 方法,如下列程式代碼範例所示。

STDMETHOD(DrawGlyphRun)(
        __maybenull void* clientDrawingContext,
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
        __maybenull IUnknown* clientDrawingEffect
        ) PURE;

此版本包含更多當您實 作自定義文字轉譯器時很有用的參數。 最後一個參數用於應用程式實作的自定義繪圖效果。 (如需用戶端繪圖效果的詳細資訊,請參閱 如何將用戶端繪圖效果新增至文字版面配置

每個圖像執行都會從原點開始,並放在從這個原始來源開始的一行。 目前世界轉換和相關聯轉譯目標上選取的文字轉譯設定會變更字元。 此 API 通常只會由執行自己版面配置的應用程式(例如 Word Processor)或已實 作 IDWriteTextRenderer 介面的應用程式直接呼叫。

DirectWrite 和 Direct2D

Direct2D 透過 DrawGlyphRun 提供圖像層級轉譯服務。 不過,這需要應用程式實作轉譯的詳細數據,這基本上會自行從 GDI 重現 DrawText API 的功能

因此,Direct2D 提供接受文字而非字元的 API:ID2D1RenderTarget::D rawTextLayout ID2D1RenderTarget::D rawText。 這兩種方法都會轉譯為 Direct2D 介面。 若要轉譯至 GDI 表面,則會提供IDWriteBitmapRenderTarget::D rawGlyphRun 但此方法需要應用程式實作自定義文字轉譯器。 (如需詳細資訊,請參閱 轉譯為 GDI Surface 主題。

例如,應用程式的文字使用方式通常會簡單:將 [確定] 或 [取消] 放在固定版面配置按鈕上。 不過,隨著國際化和其他功能的加入,隨著時間推移,它變得更加複雜。 最後,許多應用程式都必須使用 DirectWrite 的 文字配置物件,並實作文字轉譯器。

因此,Direct2D 會提供分層 API,讓應用程式能夠簡單地啟動並變得更複雜,而不需要回溯或放棄其工作程序代碼。 下圖顯示簡化的檢視:

directwrite 和 direct2d 應用程式圖表。

DrawText

DrawText 是使用的最簡單 API。 它會採用 Unicode 字串、前景筆刷、單一格式物件和目的矩形。 它會配置和轉譯配置矩形內的整個字串,並選擇性地裁剪它。 當您將簡單的文字片段放在固定版面配置 UI 中時,這會很有用。

DrawTextLayout

藉由建立 IDWriteTextLayout 物件,應用程式可以開始測量及排列文字和其他UI元素,並支援多個字型、樣式、底線和刪除線。 Direct2D 提供 DrawTextLayout API,可直接接受這個物件,並在指定時間點呈現文字。 (寬度和高度是由版面配置物件提供)。 除了實作所有預期的文字版面配置功能之外,Direct2D 還會將任何效果物件解譯為筆刷,並將該筆刷套用至選取的字元範圍。 它也會呼叫任何內嵌物件。 然後,如果應用程式想要的話,可以將非字元字元(圖示)插入文字中。 使用文字配置物件的另一個優點是圖像位置會快取於其中。 因此,藉由針對多個繪製呼叫重複使用相同的版面配置物件,並避免重新計算每個呼叫的字元位置,就可以取得較大的效能提升。 GDI 的 DrawText 不存在這項功能。

DrawGlyphRun

最後,應用程式可以實作IDWriteTextRenderer介面本身,並呼叫 DrawGlyphRun FillRectangle 本身或任何其他轉譯 API。 與文字版面配置物件的所有現有互動都會保持不變。

如需如何實作自定義文字轉譯器的範例,請參閱 使用自定義文字轉譯器來轉譯 主題。

圖像轉譯

將 DirectWrite 新增至現有的 GDI 應用程式可讓應用程式使用 IDWriteBitmapRenderTarget API 來轉譯字元。 DirectWrite 提供的 IDWriteBitmapRenderTarget::D rawGlyphRun 方法會將純色呈現至記憶體 DC,而不需要任何其他 API,例如 Direct2D

這可讓應用程式取得進階文字轉譯功能,例如:

  • 子圖元 ClearType 可讓應用程式將圖像放在子圖元位置,以允許尖銳圖像轉譯和圖像配置。
  • Y 方向的反鋸齒功能可讓您更順暢地呈現較大的圖像上的曲線。

移至 Direct2D 的應用程式也會取得下列功能:

  • 硬體加速:
  • 能夠使用任意 Direct2D 筆刷填滿文字,例如星形漸層、線性漸層和點陣陣圖。
  • 更多支援透過PushAxisAlignedClipPushLayer和 CreateCompatibleRenderTarget API 進行分層和裁剪。
  • 支援灰階文字轉譯的能力。 這會根據文字筆刷不透明度和文字的反鋸齒,正確填入目的地 Alpha 色板。

為了有效率地支持硬體加速, Direct2D 會使用稍微不同的近似值,稱為 Alpha 校正的 Gamma 校正。 這不需要 Direct2D 在轉譯文字時檢查轉譯目標色彩圖元。

結論

本主題說明 Direct2DDirectWrite 之間的差異和相似性,以及提供它們作為個別合作 API 的架構動機。