次の方法で共有


Direct2D とDirectWriteを使用したテキスト レンダリング

GDI、GDI+、WPF などの他の API とは異なり、Direct2D は別の API DirectWriteと相互運用してテキストを操作およびレンダリングします。 このトピックでは、これらの個別のコンポーネントの利点と相互運用について説明します。

このトピックは、次のセクションで構成されています。

Direct2D により増分導入が可能

あるグラフィックス API から別のグラフィックス API にアプリケーションを移動するのは困難な場合や、さまざまな理由で必要なアプリケーションではない場合があります。 これは、アプリケーション自体が大きすぎて 1 つのリリースで新しい API に移植できないため、または新しい API の一部が望ましいが、古い API がアプリケーションの他の部分に十分に機能しているために、古いインターフェイスを引き続き使用するプラグインをサポートする必要がある可能性があります。

Direct2DDirectWriteは個別のコンポーネントとして実装されているため、2D グラフィックス システム全体またはそのテキスト部分のみをアップグレードできます。 たとえば、テキストにDirectWriteを使用するようにアプリケーションを更新しても、レンダリングには GDI または GDI+ を使用できます。

テキスト サービスとテキスト レンダリング

アプリケーションが進化するにつれて、テキスト処理の要件はますます複雑になっています。 最初は、テキストは一般的に静的にレイアウトされた UI に限定され、テキストはボタンなどの明確に定義されたボックスにレンダリングされていました。 アプリケーションがますます多くの言語で使用できるようになるにつれて、翻訳されたテキストの幅と高さの両方が言語によって大きく異なる可能性があるため、このアプローチを維持することはより困難になりました。 適応するために、アプリケーションは、逆ではなく、テキストの実際のレンダリングサイズに依存するように UI を動的にレイアウトし始めました。

アプリケーションがこのタスクを完了できるように、DirectWriteIDWriteTextLayout インターフェイスを提供します。 この API を使用すると、アプリケーションは、さまざまなフォントとフォント サイズ、下線、取り消し線、双方向テキスト、効果、省略記号、さらには埋め込まれたグリフ以外の文字 (ビットマップ絵文字やアイコンなど) などの複雑な特性を持つテキストの一部を指定できます。 その後、アプリケーションは、UI レイアウトを反復的に決定するテキストのさまざまな特性を変更できます。 DirectWrite Hello World サンプルは、次の図と「チュートリアル: DirectWriteを使用したはじめに」トピックに示されています。これらの効果の多くが示されています。

レイアウトでは、(WPF のように) グリフの幅に基づいてグリフを配置することも、グリフを最も近いピクセル位置 ( GDI のように) にスナップすることもできます。

テキスト測定を取得するだけでなく、アプリケーションはテキストのさまざまな部分をヒットテストすることができます。 たとえば、テキスト内のハイパーリンクがクリックされたことを知りたい場合があります。 (ヒット テストの詳細については、「 テキスト レイアウトでヒット テストを実行する方法 」トピックを参照してください)。

次の図に示すように、テキスト レイアウト インターフェイスは、アプリケーションが使用するレンダリング API から切り離されています。

テキスト レイアウトとグラフィックス API 図。

この分離が可能なのは、DirectWriteがレンダリング インターフェイス (IDWriteTextRenderer) を提供するためです。アプリケーションは、必要なグラフィックス API を使用してテキストをレンダリングするために実装できます。 アプリケーションで実装された IDWriteTextRenderer::D rawGlyphRun コールバック メソッドは、テキスト レイアウトをレンダリングするときにDirectWriteによって呼び出されます。 このメソッドは、描画操作を実行するか、それらを渡す必要があります。

描画グリフの場合、Direct2DDirect2D サーフェスへの描画に ID2D1RenderTarget::D rawGlyphRun を提供し、DirectWriteは GDI サーフェスに描画するために IDWriteBitmapRenderTarget::D rawGlyphRun を提供し、GDI を使用してウィンドウに転送できます。 便利なことに、Direct2D と DirectWrite の両方で DrawGlyphRun には、アプリケーションが IDWriteTextRenderer に実装する DrawGlyphRun メソッドと正確に互換性のあるパラメーターがあります。

同様の分離の後、テキスト固有の機能 (フォント列挙や管理、グリフ分析など) は、Direct2D ではなく DirectWrite によって処理されます。 DirectWrite オブジェクトは Direct2D によって直接受け入れられます。 既存の GDI アプリケーションでDirectWriteを利用できるようにするために、IDWriteGdiInterop メソッド インターフェイスに次の操作を行うメソッドが用意されています。

グリフとテキスト

Text は Unicode コード ポイント (文字) のセットであり、さまざまなスタイル修飾子 (フォント、重み、下線、取り消し線など) が四角形に配置されます。 これに対し、グリフは特定のフォント ファイルへの特定のインデックスです。 グリフは、レンダリングできる一連の曲線を定義しますが、テキスト的な意味はありません。 グリフと文字の間に多対多マッピングが存在する可能性があります。 同じ Font Face から取得され、ベースラインに順番にレイアウトされるグリフのシーケンスは 、GlyphRun と呼ばれます。 DirectWriteDirect2D はどちらも、最も正確なグリフ レンダリング 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;

このメソッドは、DirectWriteIDWriteBitmapRenderTarget からのメソッドです。

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 プロセッサなど) または IDWriteTextRenderer インターフェイスを実装したアプリケーションによってのみ直接呼び出されます。

DirectWriteと Direct2D

Direct2D では、 DrawGlyphRun を介したグリフ レベルのレンダリング サービスが提供されます。 ただし、これには、基本的に GDI からの DrawText API の機能を独自に再現するレンダリングの詳細を実装する必要があります。

したがって、 Direct2D には、グリフの代わりにテキストを受け入れる API ID2D1RenderTarget::D rawTextLayoutID2D1RenderTarget::D rawText が用意されています。 どちらのメソッドも Direct2D サーフェスにレンダリングされます。 GDI サーフェスにレンダリングするために、 IDWriteBitmapRenderTarget::D rawGlyphRun が提供されます。 ただし、このメソッドでは、カスタム テキスト レンダラーをアプリケーションによって実装する必要があります。 (詳細については、「 GDI Surface にレンダリングする 」トピックを参照してください)。

通常、アプリケーションのテキストの使用は単純になります。たとえば、固定レイアウト ボタンに [OK] または [キャンセル] を設定します。 ただし、時間が経つにつれて、国際化やその他の機能が追加されるにつれて複雑になります。 最終的には、多くのアプリケーションでDirectWriteのテキスト レイアウト オブジェクトを使用し、テキスト レンダラーを実装する必要があります。

そのため、 Direct2D では、アプリケーションを単純に開始し、動作するコードをバックトラックしたり破棄したりすることなく、より高度に拡張できる階層化された API が提供されます。 簡略化されたビューを次の図に示します。

directwrite と direct2d アプリケーションの図。

Drawtext

DrawText は、使用する API の中で最も簡単です。 Unicode 文字列、前景ブラシ、1 つの書式オブジェクト、変換先の四角形を受け取ります。 レイアウト四角形内に文字列全体をレイアウトしてレンダリングし、必要に応じてクリップします。 これは、固定レイアウト UI の一部に単純なテキストを配置する場合に便利です。

DrawTextLayout

IDWriteTextLayout オブジェクトを作成することで、アプリケーションはテキストとその他の UI 要素の測定と配置を開始し、複数のフォント、スタイル、下線、取り消し線をサポートできます。 Direct2D は、このオブジェクトを直接受け入れ、特定のポイントでテキストをレンダリングする DrawTextLayout API を提供します。 (幅と高さはレイアウト オブジェクトによって提供されます)。 Direct2D は、予想されるすべてのテキスト レイアウト機能を実装するだけでなく、効果オブジェクトをブラシとして解釈し、そのブラシを選択したグリフの範囲に適用します。 また、インライン オブジェクトも呼び出します。 アプリケーションでは、必要に応じて、グリフ以外の文字 (アイコン) をテキストに挿入できます。 テキスト レイアウト オブジェクトを使用するもう 1 つの利点は、グリフの位置がキャッシュされていることです。 したがって、同じレイアウト オブジェクトを複数の描画呼び出しに再利用し、各呼び出しのグリフ位置を再計算しないようにすることで、パフォーマンスが大幅に向上します。 この機能は、GDI の DrawText には存在しません。

DrawGlyphRun

最後に、アプリケーションは IDWriteTextRenderer インターフェイス自体を実装し、 DrawGlyphRun および FillRectangle 自体、またはその他のレンダリング API を呼び出すことができます。 Text Layout オブジェクトに対する既存の操作はすべて変更されません。

カスタム テキスト レンダラーを実装する方法の例については、「カスタム テキスト レンダラーを 使用してレンダリングする 」トピックを参照してください。

グリフレンダリング

既存 GDI アプリケーションにDirectWriteを追加すると、アプリケーションは IDWriteBitmapRenderTarget API を使用してグリフをレンダリングできます。 DirectWriteが提供する IDWriteBitmapRenderTarget::D rawGlyphRun メソッドは、Direct2D などの追加の API を必要とせずに、単色でメモリ DC にレンダリングされます。

これにより、アプリケーションは次のような高度なテキスト レンダリング機能を取得できます。

  • サブピクセル ClearType を使用すると、アプリケーションはサブピクセル位置にグリフを配置して、シャープなグリフレンダリングとグリフレイアウトの両方を可能にします。
  • Y 方向アンチエイリアシングを使用すると、より大きなグリフで曲線をよりスムーズにレンダリングできます。

Direct2D に移行するアプリケーションでは、次の機能も取得されます。

  • ハードウェアの高速化
  • 放射状グラデーション、線形グラデーション、ビットマップなど、任意の Direct2D ブラシでテキストを塗りつぶす機能。
  • PushAxisAlignedClipPushLayerCreateCompatibleRenderTarget API を介したレイヤー化とクリッピングのサポートが強化されました。
  • グレースケールテキストレンダリングをサポートする機能。 これにより、テキスト ブラシの不透明度とテキストのアンチエイリアシングの両方に従って、宛先のアルファ チャネルが正しく設定されます。

ハードウェア アクセラレーションを効率的にサポートするために、 Direct2D では アルファ補正と呼ばれるガンマ補正とは若干異なる近似値が使用されます。 テキストをレンダリングするときに、Direct2D でレンダー ターゲットのカラー ピクセルを検査する必要はありません。

まとめ

このトピックでは、Direct2DDirectWriteの違いと類似点、およびそれらを個別の協調 API として提供するためのアーキテクチャ上の動機について説明します。