다음을 통해 공유


텍스트 레이아웃에 인라인 개체를 추가하는 방법

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 메서드는 모든 0을 반환합니다.

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 클래스의 instance 만들고 텍스트 레이아웃에 추가합니다. 디바이스 종속 리소스인 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_);