テキスト レイアウトにクライアント描画効果を追加する方法
IDWriteTextLayout インターフェイスとカスタム テキスト レンダラーを使用してテキストを表示するDirectWrite アプリケーションにクライアント描画効果を追加する簡単なチュートリアルを提供します。
このチュートリアルの最後の製品は、次のスクリーン ショットに示すように、それぞれ異なる色描画効果を持つテキストの範囲を持つテキストを表示するアプリケーションです。
注意
このチュートリアルは、カラー テキストを描画するための簡単な方法の例ではなく、カスタム クライアント描画効果を作成する方法の簡略化された例を意味します。 詳細については、 IDWriteTextLayout::SetDrawingEffect リファレンス ページを参照してください。
このチュートリアルには、次の部分が含まれています。
- 手順 1: テキスト レイアウトを作成する
- 手順 2: カスタム描画効果クラスを実装する
- 手順 3: カスタム テキスト レンダラー クラスを実装する
- 手順 4: テキスト レンダラーを作成する
- 手順 5: カラー描画効果オブジェクトをインスタンス化する
- 手順 6: 特定のテキスト範囲の描画効果を設定する
- 手順 7: カスタム レンダラーを使用してテキスト レイアウトを描画する
- 手順 8: クリーンアップする
手順 1: テキスト レイアウトを作成する
まず、 IDWriteTextLayout オブジェクトを持つアプリケーションが必要です。 テキスト レイアウトでテキストを表示するアプリケーションが既にある場合、または Custom DrawingEffect Example Code を使用している場合は、手順 2 に進みます。
テキスト レイアウトを追加するには、次の操作を行う必要があります。
IDWriteTextLayout インターフェイスへのポインターを クラスのメンバーとして宣言します。
IDWriteTextLayout* pTextLayout_;
CreateDeviceIndependentResources メソッドの最後に、CreateTextLayout メソッドを呼び出して IDWriteTextLayout インターフェイス オブジェクトを作成します。
// Create a text layout using the text format. if (SUCCEEDED(hr)) { RECT rect; GetClientRect(hwnd_, &rect); float width = rect.right / dpiScaleX_; float height = rect.bottom / dpiScaleY_; hr = pDWriteFactory_->CreateTextLayout( wszText_, // The string to be laid out and formatted. cTextLength_, // The length of the string. pTextFormat_, // The text format to apply to the string (contains font information, etc). width, // The width of the layout box. height, // The height of the layout box. &pTextLayout_ // The IDWriteTextLayout interface pointer. ); }
最後に、デストラクターでテキスト レイアウトを解放することを忘れないでください。
SafeRelease(&pTextLayout_);
手順 2: カスタム描画効果クラスを実装する
IUnknown から継承されたメソッド以外に、カスタム クライアント描画効果インターフェイスには、実装する必要がある要件はありません。 この場合、 ColorDrawingEffect クラスは 単にD2D1_COLOR_F 値を保持し、この値を取得および設定するメソッドと、最初に色を設定できるコンストラクターを宣言します。
IDWriteTextLayout オブジェクトのテキスト範囲にクライアント描画効果が適用されると、描画効果は、レンダリングされるグリフ実行の IDWriteTextRenderer::D rawGlyphRun メソッドに渡されます。 描画効果のメソッドは、テキスト レンダラーで使用できます。
クライアント描画効果は、この例よりも多くの情報を保持し、グリフを変更したり、描画に使用するオブジェクトを作成したりするためのメソッドを提供したりして、作成するのと同じくらい複雑な場合があります。
手順 3: カスタム テキスト レンダラー クラスを実装する
クライアント描画効果を利用するには、カスタム テキスト レンダラーを実装する必要があります。 このテキスト レンダラーは、 IDWriteTextLayout::D raw メソッドによって渡された描画効果を、描画中のグリフ実行に適用します。
コンストラクター
カスタム テキスト レンダラーのコンストラクターには、Direct2D オブジェクトの作成に使用される ID2D1Factory オブジェクトと、テキストが描画される Direct2D レンダー ターゲットが格納されます。
CustomTextRenderer::CustomTextRenderer(
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT
)
:
cRefCount_(0),
pD2DFactory_(pD2DFactory),
pRT_(pRT)
{
pD2DFactory_->AddRef();
pRT_->AddRef();
}
DrawGlyphRun メソッド
グリフ実行は、クライアント描画効果を含め、同じ形式を共有するグリフのセットです。 DrawGlyphRun メソッドは、指定されたグリフ実行のテキスト レンダリングを処理します。
まず、 ID2D1PathGeometry と ID2D1GeometrySink を作成し、 IDWriteFontFace::GetGlyphRunOutline を使用してグリフ実行アウトラインを取得します。 次に、次のコードに示すように、Direct2D ID2D1Factory::CreateTransformedGeometry メソッドを使用してジオメトリの原点を変換します。
HRESULT hr = S_OK;
// Create the path geometry.
ID2D1PathGeometry* pPathGeometry = NULL;
hr = pD2DFactory_->CreatePathGeometry(
&pPathGeometry
);
// Write to the path geometry using the geometry sink.
ID2D1GeometrySink* pSink = NULL;
if (SUCCEEDED(hr))
{
hr = pPathGeometry->Open(
&pSink
);
}
// Get the glyph run outline geometries back from DirectWrite and place them within the
// geometry sink.
if (SUCCEEDED(hr))
{
hr = glyphRun->fontFace->GetGlyphRunOutline(
glyphRun->fontEmSize,
glyphRun->glyphIndices,
glyphRun->glyphAdvances,
glyphRun->glyphOffsets,
glyphRun->glyphCount,
glyphRun->isSideways,
glyphRun->bidiLevel%2,
pSink
);
}
// Close the geometry sink
if (SUCCEEDED(hr))
{
hr = pSink->Close();
}
// Initialize a matrix to translate the origin of the glyph run.
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
// Create the transformed geometry
ID2D1TransformedGeometry* pTransformedGeometry = NULL;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pPathGeometry,
&matrix,
&pTransformedGeometry
);
}
次に、 Direct2D ソリッド ブラシ オブジェクトを宣言します。
ID2D1SolidColorBrush* pBrush = NULL;
clientDrawingEffect パラメーターが NULL でない場合は、ColorDrawingEffect インターフェイスのオブジェクトに対してクエリを実行します。 これは、このクラスを、テキスト レイアウト オブジェクトのテキスト範囲に対するクライアント描画効果として設定するため、機能します。
ColorDrawingEffect インターフェイスへのポインターを取得したら、GetColor メソッドを使用して格納するD2D1_COLOR_F値を取得できます。 次に、 D2D1_COLOR_F を使用して、その色で ID2D1SolidColorBrush を作成します。
clientDrawingEffect パラメーターが NULL の場合は、黒い ID2D1SolidColorBrush を作成するだけです。
// If there is a drawing effect create a color brush using it, otherwise create a black brush.
if (clientDrawingEffect != NULL)
{
// Go from IUnknown to ColorDrawingEffect.
ColorDrawingEffect *colorDrawingEffect;
clientDrawingEffect->QueryInterface(__uuidof(ColorDrawingEffect), reinterpret_cast<void**>(&colorDrawingEffect));
// Get the color from the ColorDrawingEffect object.
D2D1_COLOR_F color;
colorDrawingEffect->GetColor(&color);
// Create the brush using the color specified by our ColorDrawingEffect object.
if (SUCCEEDED(hr))
{
hr = pRT_->CreateSolidColorBrush(
color,
&pBrush);
}
SafeRelease(&colorDrawingEffect);
}
else
{
// Create a black brush.
if (SUCCEEDED(hr))
{
hr = pRT_->CreateSolidColorBrush(
D2D1::ColorF(
D2D1::ColorF::Black
),
&pBrush);
}
}
最後に、アウトライン ジオメトリを描画し、先ほど作成した純色ブラシを使用して塗りつぶします。
if (SUCCEEDED(hr))
{
// Draw the outline of the glyph run
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush
);
// Fill in the glyph run
pRT_->FillGeometry(
pTransformedGeometry,
pBrush
);
}
デストラクター
Direct2D ファクトリを解放し、デストラクターでターゲットをレンダリングすることを忘れないでください。
CustomTextRenderer::~CustomTextRenderer()
{
SafeRelease(&pD2DFactory_);
SafeRelease(&pRT_);
}
手順 4: テキスト レンダラーを作成する
CreateDeviceDependent リソースで、カスタム テキスト レンダラー オブジェクトを作成します。 ID2D1RenderTarget を使用するため、デバイスに依存します。 ID2D1RenderTarget 自体はデバイスに依存します。
// Create the text renderer
pTextRenderer_ = new CustomTextRenderer(
pD2DFactory_,
pRT_
);
手順 5: カラー描画効果オブジェクトをインスタンス化する
ColorDrawingEffect オブジェクトを赤、緑、青でインスタンス化します。
// Instantiate some custom color drawing effects.
redDrawingEffect_ = new ColorDrawingEffect(
D2D1::ColorF(
D2D1::ColorF::Red
)
);
blueDrawingEffect_ = new ColorDrawingEffect(
D2D1::ColorF(
D2D1::ColorF::Blue
)
);
greenDrawingEffect_ = new ColorDrawingEffect(
D2D1::ColorF(
D2D1::ColorF::Green
)
);
手順 6: 特定のテキスト範囲の描画効果を設定する
IDWriteTextLayou::SetDrawingEffect メソッドと DWRITE_TEXT_RANGE 構造体を使用して、特定のテキスト範囲の描画効果を設定します。
// Set the drawing effects.
// Red.
if (SUCCEEDED(hr))
{
// Set the drawing effect for the specified range.
DWRITE_TEXT_RANGE textRange = {0,
14};
if (SUCCEEDED(hr))
{
hr = pTextLayout_->SetDrawingEffect(redDrawingEffect_, textRange);
}
}
// Blue.
if (SUCCEEDED(hr))
{
// Set the drawing effect for the specified range.
DWRITE_TEXT_RANGE textRange = {14,
7};
if (SUCCEEDED(hr))
{
hr = pTextLayout_->SetDrawingEffect(blueDrawingEffect_, textRange);
}
}
// Green.
if (SUCCEEDED(hr))
{
// Set the drawing effect for the specified range.
DWRITE_TEXT_RANGE textRange = {21,
8};
if (SUCCEEDED(hr))
{
hr = pTextLayout_->SetDrawingEffect(greenDrawingEffect_, textRange);
}
}
手順 7: カスタム レンダラーを使用してテキスト レイアウトを描画する
ID2D1RenderTarget::D rawText メソッドまたは ID2D1RenderTarget::D rawTextLayout メソッドではなく、IDWriteTextLayout::D raw メソッドを呼び出す必要があります。
// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
NULL,
pTextRenderer_, // Custom text renderer.
origin.x,
origin.y
);
手順 8: クリーンアップする
DemoApp デストラクターで、カスタム テキスト レンダラーを解放します。
SafeRelease(&pTextRenderer_);
その後、クライアント描画効果クラスを解放するコードを追加します。
SafeRelease(&redDrawingEffect_);
SafeRelease(&blueDrawingEffect_);
SafeRelease(&greenDrawingEffect_);