次の方法で共有


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 サンプルは、次の図と「Tutorial: DirectWrite の概要」のトピックに示されています。

「hello world」サンプルのスクリーン ショット。

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

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

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

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

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

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

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

グリフとテキスト

テキストは、さまざまなスタイル修飾子 (フォント、太さ、下線、取り消し線など) が付いた、四角形内に配置された Unicode コード ポイント (文字) のセットです。 対照的に、グリフは特定のフォント ファイルへの特定のインデックスです。 グリフはレンダリング可能な曲線のセットを定義しますが、テキスト上の意味はありません。 グリフと文字の間には、多対多のマッピングが存在する可能性があります。 同じフォント フェイスから取得され、ベースラインに順番にレイアウトされるグリフのシーケンスは、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 は通常、独自のレイアウトを実行するアプリケーション (ワード プロセッサなど) または IDWriteTextRenderer インターフェイスを実装したアプリケーションによってのみ、直接呼び出されます。

DirectWrite と Direct2D

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

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

通常、アプリケーションによるテキストの使用は、たとえば、固定レイアウトのボタンに [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 を呼び出すことができます。 テキスト レイアウト オブジェクトとの既存のすべてのやり取りは変わりません。

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

グリフ レンダリング

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

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

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

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

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

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

まとめ

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