다음을 통해 공유


사용자 지정 텍스트 렌더러를 사용하여 렌더링

idWriteTextRenderer에서 파생된 사용자 지정 텍스트 렌더러에서 DirectWrite텍스트 레이아웃을 그릴 수 있습니다. 사용자 지정 렌더러는 비트맵 또는 GDI 표면에 렌더링, 인라인 개체 및 클라이언트 그리기 효과와 같은 DirectWrite 일부 고급 기능을 활용해야 합니다. 이 자습서에서는 IDWriteTextRenderer의 메서드를 설명하고 Direct2D 를 사용하여 비트맵 채우기로 텍스트를 렌더링하는 예제 구현을 제공합니다.

이 자습서에는 다음 부분이 포함되어 있습니다.

사용자 지정 텍스트 렌더러는 IDWriteTextRenderer 참조 페이지 이하에 나열된 메서드 외에도 IUnknown에서 상속된 메서드를 구현해야 합니다.

사용자 지정 텍스트 렌더러에 대한 전체 소스 코드는 DirectWrite 헬로 월드 샘플의 CustomTextRenderer.cpp 및 CustomTextRenderer.h 파일을 참조하세요.

생성자

사용자 지정 텍스트 렌더러에는 생성자가 필요합니다. 이 예제에서는 단색 및 비트맵 Direct2D 브러시를 모두 사용하여 텍스트를 렌더링합니다.

이 때문에 생성자는 설명과 함께 아래 표에 있는 매개 변수를 사용합니다.

매개 변수 설명
pD2DFactory 필요한 Direct2D 리소스를 만드는 데 사용할 ID2D1Factory 개체에 대한 포인터입니다.
Prt 텍스트가 렌더링될 ID2D1HwndRenderTarget 개체에 대한 포인터입니다.
pOutlineBrush 텍스트의 윤곽선을 그리는 데 사용할 ID2D1SolidColorBrush 에 대한 포인터입니다.
pFillBrush 텍스트를 채우는 데 사용할 ID2D1BitmapBrush 에 대한 포인터입니다.

 

다음 코드와 같이 생성자가 저장합니다.

CustomTextRenderer::CustomTextRenderer(
    ID2D1Factory* pD2DFactory, 
    ID2D1HwndRenderTarget* pRT, 
    ID2D1SolidColorBrush* pOutlineBrush, 
    ID2D1BitmapBrush* pFillBrush
    )
:
cRefCount_(0), 
pD2DFactory_(pD2DFactory), 
pRT_(pRT), 
pOutlineBrush_(pOutlineBrush), 
pFillBrush_(pFillBrush)
{
    pD2DFactory_->AddRef();
    pRT_->AddRef();
    pOutlineBrush_->AddRef();
    pFillBrush_->AddRef();
}

DrawGlyphRun()

DrawGlyphRun 메서드는 텍스트 렌더러의 기본 콜백 메서드입니다. 기준선 원본 및 측정 모드와 같은 정보 외에도 렌더링할 문자 모양 실행을 전달합니다. 또한 문자 모양 실행에 적용할 클라이언트 그리기 효과 개체를 전달합니다. 자세한 내용은 텍스트 레이아웃에 클라이언트 그리기 효과를 추가하는 방법 항목을 참조하세요.

이 텍스트 렌더러 구현은 문자 모양을 Direct2D 기하 도형으로 변환한 다음 기하 도형을 그리기 및 채우면 문자 모양 실행을 렌더링합니다. 이 단계는 다음 단계로 구성됩니다.

  1. ID2D1PathGeometry 개체를 만든 다음 ID2D1PathGeometry::Open 메서드를 사용하여 ID2D1GeometrySink 개체를 검색합니다.

    // 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
            );
    }
    
  2. DrawGlyphRun에 전달되는 DWRITE_GLYPH_RUN 전체 문자 모양 실행에 대한 글꼴 얼굴을 나타내는 fontFace라는 IDWriteFontFace 개체를 포함합니다. 다음 코드와 같이 IDWriteFontFace:: GetGlyphRunOutline 메서드를 사용하여 기하 도형 싱크에 문자 모양 실행의 윤곽선을 배치합니다.

    // 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
            );
    }
    
  3. 기하 도형 싱크를 채운 후 닫습니다.

    // Close the geometry sink
    if (SUCCEEDED(hr))
    {
        hr = pSink->Close();
    }
    
  4. 문자 모양 실행의 원점은 다음 코드와 같이 올바른 기준선 원본에서 렌더링되도록 변환되어야 합니다.

    // 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
        );
    

    baselineOriginXbaselineOriginYDrawGlyphRun 콜백 메서드에 매개 변수로 전달됩니다.

  5. ID2D1Factory::CreateTransformedGeometry 메서드를 사용하고 경로 기하 도형 및 변환 행렬을 전달하여 변환된 기하 도형을 만듭니다.

    // Create the transformed geometry
    ID2D1TransformedGeometry* pTransformedGeometry = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory_->CreateTransformedGeometry(
            pPathGeometry,
            &matrix,
            &pTransformedGeometry
            );
    }
    
  6. 마지막으로 변환된 기하 도형의 윤곽선을 그리고 ID2D1RenderTarget::D rawGeometryID2D1RenderTarget::FillGeometry 메서드 및 멤버 변수로 저장된 Direct2D 브러시를 사용하여 채웁니다.

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  7. 이제 그리기를 마쳤으므로 이 메서드에서 만든 개체를 클린 것을 잊지 마세요.

    SafeRelease(&pPathGeometry);
    SafeRelease(&pSink);
    SafeRelease(&pTransformedGeometry);
    

DrawUnderline() 및 DrawStrikethrough()

IDWriteTextRenderer 에는 밑줄 및 취소선을 그리기 위한 콜백도 있습니다. 다음은 밑줄이나 취소선에 대한 간단한 사각형을 그리는 예제이지만 다른 셰이프를 그릴 수 있습니다.

Direct2D를 사용하여 밑줄을 그리는 작업은 다음 단계로 구성됩니다.

  1. 먼저 밑줄의 크기와 모양의 D2D1_RECT_F 구조를 만듭니다. DrawUnderline 콜백 메서드에 전달되는 DWRITE_UNDERLINE 구조체는 밑줄의 오프셋, 너비 및 두께를 제공합니다.

    D2D1_RECT_F rect = D2D1::RectF(
        0,
        underline->offset,
        underline->width,
        underline->offset + underline->thickness
        );
    
  2. 다음으로 ID2D1Factory::CreateRectangleGeometry 메서드 및 초기화된 D2D1_RECT_F 구조를 사용하여 ID2D1RectangleGeometry 개체를 만듭니다.

    ID2D1RectangleGeometry* pRectangleGeometry = NULL;
    hr = pD2DFactory_->CreateRectangleGeometry(
            &rect, 
            &pRectangleGeometry
            );
    
  3. 문자 모양 실행과 마찬가지로 CreateTransformedGeometry 메서드를 사용하여 기준선 원점 값에 따라 밑줄 기하 도형의 원점이 변환되어야 합니다.

    // Initialize a matrix to translate the origin of the underline
    D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
        1.0f, 0.0f,
        0.0f, 1.0f,
        baselineOriginX, baselineOriginY
        );
    
    ID2D1TransformedGeometry* pTransformedGeometry = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory_->CreateTransformedGeometry(
            pRectangleGeometry,
            &matrix,
            &pTransformedGeometry
            );
    }
    
  4. 마지막으로 변환된 기하 도형의 윤곽선을 그리고 ID2D1RenderTarget::D rawGeometryID2D1RenderTarget::FillGeometry 메서드 및 멤버 변수로 저장된 Direct2D 브러시를 사용하여 채웁니다.

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  5. 이제 그리기를 마쳤으므로 이 메서드에서 만든 개체를 클린 것을 잊지 마세요.

    SafeRelease(&pRectangleGeometry);
    SafeRelease(&pTransformedGeometry);
    

취소선을 그리는 프로세스는 동일합니다. 그러나 취소선은 오프셋이 다르며 너비와 두께가 다를 수 있습니다.

픽셀 맞춤, DIP당 픽셀 및 변환

IsPixelSnappingDisabled()

이 메서드는 픽셀 스냅을 사용하지 않도록 설정되었는지 여부를 확인하기 위해 호출됩니다. 권장되는 기본값은 FALSE이며 이 예제의 출력입니다.

*isDisabled = FALSE;

GetCurrentTransform()

다음은 Direct2D 렌더링 대상에 렌더링되므로 ID2D1RenderTarget::GetTransform을 사용하여 렌더링 대상에서 변환을 전달합니다.

//forward the render target's transform
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));

GetPixelsPerDip()

이 메서드는 DIP(디바이스 독립 픽셀)당 픽셀 수를 가져오기 위해 호출됩니다.

float x, yUnused;

pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;

DrawInlineObject()

사용자 지정 텍스트 렌더러에는 인라인 개체를 그리기 위한 콜백도 있습니다. 이 예제에서 DrawInlineObject 는 E_NOTIMPL 반환합니다. 인라인 개체를 그리는 방법에 대한 설명은 이 자습서의 scope. 자세한 내용은 텍스트 레이아웃에 인라인 개체를 추가하는 방법 항목을 참조하세요.

소멸자

사용자 지정 텍스트 렌더러 클래스에서 사용한 포인터를 해제하는 것이 중요합니다.

CustomTextRenderer::~CustomTextRenderer()
{
    SafeRelease(&pD2DFactory_);
    SafeRelease(&pRT_);
    SafeRelease(&pOutlineBrush_);
    SafeRelease(&pFillBrush_);
}

사용자 지정 텍스트 렌더러 사용

다음 코드와 같이 IDWriteTextRenderer에서 파생된 콜백 인터페이스를 인수로 사용하는 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
        );

IDWriteTextLayout::D raw 메서드는 사용자가 제공하는 사용자 지정 렌더러 콜백의 메서드를 호출합니다. 위에서 설명한 DrawGlyphRun, DrawUnderline, DrawInlineObjectDrawStrikethrough 메서드는 그리기 함수를 수행합니다.