テキスト レイアウトにインライン オブジェクトを追加する方法
IDWriteTextLayout インターフェイスを使用してテキストを表示するDirectWrite アプリケーションにインライン オブジェクトを追加する簡単なチュートリアルを提供します。
このチュートリアルの最後の製品は、次のスクリーン ショットに示すように、インライン イメージが埋め込まれたテキストを表示するアプリケーションです。
このチュートリアルには、次の部分が含まれています。
- 手順 1: テキスト レイアウトを作成する。
- 手順 2: IDWriteInlineObject インターフェイスから派生したクラスを定義します。
- 手順 3: インライン オブジェクト クラスを実装する。
- 手順 4: InlineImage クラスのインスタンスを作成し、テキスト レイアウトに追加します。
手順 1: テキスト レイアウトを作成する。
まず、 IDWriteTextLayout オブジェクトを持つアプリケーションが必要です。 テキスト レイアウトを含むテキストを表示するアプリケーションが既にある場合は、手順 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. ); }
次に、次のコードに示すように 、ID2D1RenderTarget::D rawText メソッドの呼び出しを ID2D1RenderTarget::D rawTextLayout に変更する必要があります。
pRT_->DrawTextLayout( origin, pTextLayout_, pBlackBrush_ );
手順 2: IDWriteInlineObject インターフェイスから派生したクラスを定義します。
DirectWriteでのインライン オブジェクトのサポートは、IDWriteInlineObject インターフェイスによって提供されます。 インライン オブジェクトを使用するには、このインターフェイスを実装する必要があります。 インライン オブジェクトの描画を処理し、メトリックやその他の情報をレンダラーに提供します。
新しいヘッダー ファイルを作成し、 IDWriteInlineObject から派生した InlineImage というインターフェイスを宣言します。
IUnknown から継承された QueryInterface、AddRef、Release に加えて、このクラスには次のメソッドが必要です。
手順 3: インライン オブジェクト クラスを実装する。
クラス実装用に InlineImage.cpp という名前の新しい C++ ファイルを作成します。 LoadBitmapFromFile メソッドと IUnknown インターフェイスから継承されたメソッドに加えて、InlineImage クラスは次のメソッドで構成されます。
コンストラクター。
InlineImage::InlineImage(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR uri
)
{
// Save the render target for later.
pRT_ = pRenderTarget;
pRT_->AddRef();
// Load the bitmap from a file.
LoadBitmapFromFile(
pRenderTarget,
pIWICFactory,
uri,
&pBitmap_
);
}
コンストラクターの最初の引数は、インライン イメージがレンダリングされる ID2D1RenderTarget です。 これは後で描画するときに使用するために保存されます。
レンダー ターゲットの IWICImagingFactory とファイル名 URI はすべて、ビットマップを読み込み、ビットマップ サイズ (幅と高さ) をrect_メンバー変数に格納する LoadBitmapFromFile メソッドに渡されます。
Draw メソッド。
Draw メソッドは、インライン オブジェクトを描画する必要がある場合に IDWriteTextRenderer オブジェクトによって呼び出されるコールバックです。 テキスト レイアウトでは、このメソッドは直接呼び出されません。
HRESULT STDMETHODCALLTYPE InlineImage::Draw(
__maybenull void* clientDrawingContext,
IDWriteTextRenderer* renderer,
FLOAT originX,
FLOAT originY,
BOOL isSideways,
BOOL isRightToLeft,
IUnknown* clientDrawingEffect
)
{
float height = rect_.bottom - rect_.top;
float width = rect_.right - rect_.left;
D2D1_RECT_F destRect = {originX, originY, originX + width, originY + height};
pRT_->DrawBitmap(pBitmap_, destRect);
return S_OK;
}
この場合、ビットマップの描画は ID2D1RenderTarget::D rawBitmap メソッドを使用して行われます。ただし、描画には任意の方法を使用できます。
GetMetrics メソッド。
HRESULT STDMETHODCALLTYPE InlineImage::GetMetrics(
__out DWRITE_INLINE_OBJECT_METRICS* metrics
)
{
DWRITE_INLINE_OBJECT_METRICS inlineMetrics = {};
inlineMetrics.width = rect_.right - rect_.left;
inlineMetrics.height = rect_.bottom - rect_.top;
inlineMetrics.baseline = baseline_;
*metrics = inlineMetrics;
return S_OK;
}
GetMetrics メソッドの場合は、幅、高さ、ベースラインをDWRITE_INLINE_OBJECT_METRICS構造体に格納します。 IDWriteTextLayout は、インライン オブジェクトの測定を取得するために、このコールバック関数を呼び出します。
GetOverhangMetrics メソッド。
HRESULT STDMETHODCALLTYPE InlineImage::GetOverhangMetrics(
__out DWRITE_OVERHANG_METRICS* overhangs
)
{
overhangs->left = 0;
overhangs->top = 0;
overhangs->right = 0;
overhangs->bottom = 0;
return S_OK;
}
この場合、オーバーハングは必要ないため、 GetOverhangMetrics メソッドはすべてのゼロを返します。
GetBreakConditions メソッド。
HRESULT STDMETHODCALLTYPE InlineImage::GetBreakConditions(
__out DWRITE_BREAK_CONDITION* breakConditionBefore,
__out DWRITE_BREAK_CONDITION* breakConditionAfter
)
{
*breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL;
*breakConditionAfter = DWRITE_BREAK_CONDITION_NEUTRAL;
return S_OK;
}
手順 4: InlineImage クラスのインスタンスを作成し、テキスト レイアウトに追加します。
最後に、CreateDeviceDependentResources メソッドで InlineImage クラスのインスタンスを作成し、テキスト レイアウトに追加します。 デバイスに依存するリソースである ID2D1RenderTarget への参照を保持し、 ID2D1Bitmap はレンダー ターゲットを使用して作成されるため、InlineImage もデバイスに依存し、レンダー ターゲットを再作成する場合は再作成する必要があります。
// Create an InlineObject.
pInlineImage_ = new InlineImage(pRT_, pWICFactory_, L"img1.jpg");
DWRITE_TEXT_RANGE textRange = {14, 1};
pTextLayout_->SetInlineObject(pInlineImage_, textRange);
IDWriteTextLayout::SetInlineObject メソッドは、テキスト範囲の構造を受け取ります。 オブジェクトはここで指定した範囲に適用され、範囲内のすべてのテキストは非表示になります。 テキスト範囲の長さが 0 の場合、オブジェクトは描画されません。
この例では、画像を表示する位置にプレース ホルダーとしてアスタリスク (*) があります。
// The string to display. The '*' character will be suppressed by our image.
wszText_ = L"Inline Object * Example";
cTextLength_ = wcslen(wszText_);
InlineImage クラスは ID2D1RenderTarget に依存するため、レンダー ターゲットを解放するときに解放する必要があります。
SafeRelease(&pInlineImage_);