次の方法で共有


テキスト レイアウトにインライン オブジェクトを追加する方法

IDWriteTextLayout インターフェイスを使用してテキストを表示するDirectWrite アプリケーションにインライン オブジェクトを追加する簡単なチュートリアルを提供します。

このチュートリアルの最後の製品は、次のスクリーン ショットに示すように、インライン イメージが埋め込まれたテキストを表示するアプリケーションです。

埋め込み画像を含む

このチュートリアルには、次の部分が含まれています。

手順 1: テキスト レイアウトを作成する。

まず、 IDWriteTextLayout オブジェクトを持つアプリケーションが必要です。 テキスト レイアウトを含むテキストを表示するアプリケーションが既にある場合は、手順 2 に進みます。

テキスト レイアウトを追加するには、次の操作を行う必要があります。

  1. IDWriteTextLayout インターフェイスへのポインターを クラスのメンバーとして宣言します。

    IDWriteTextLayout* pTextLayout_;
    
    
  2. 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.
            );
    }
    
    
  3. 次に、次のコードに示すように 、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_);