다음을 통해 공유


자습서: DirectWrite 시작

이 문서에서는 DirectWriteDirect2D를 사용하여 단일 형식을 포함하는 간단한 텍스트를 만든 다음 여러 서식이 포함된 텍스트를 만드는 방법을 보여 줍니다.

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

소스 코드

이 개요에 표시된 소스 코드는 DirectWrite 헬로 월드 샘플에서 가져옵니다. 각 파트는 별도의 클래스(SimpleText 및 MultiformattedText)에서 구현되며 별도의 자식 창에 표시됩니다. 각 클래스는 Microsoft Win32 창을 나타냅니다. WndProc 메서드 외에도 각 클래스에는 다음 메서드가 포함됩니다.

기능 Description
CreateDeviceIndependentResources 디바이스 독립적 리소스를 만들어 어디서나 재사용할 수 있습니다.
DiscardDeviceIndependentResources 더 이상 필요하지 않은 디바이스 독립적 리소스를 해제합니다.
CreateDeviceResources 특정 디바이스에 연결된 브러시 및 렌더링 대상과 같은 리소스를 만듭니다.
DiscardDeviceResources 더 이상 필요하지 않은 디바이스 종속 리소스를 해제합니다.
DrawD2DContent Direct2D를 사용하여 화면에 렌더링합니다.
Drawtext Direct2D를 사용하여 텍스트 문자열을 그립니다.
Onresize 창 크기가 변경되면 Direct2D 렌더링 대상의 크기를 조정합니다.

 

제공된 샘플을 사용하거나 다음 지침을 사용하여 사용자 고유의 Win32 애플리케이션에 DirectWriteDirect2D를 추가할 수 있습니다. 샘플 및 관련 프로젝트 파일에 대한 자세한 내용은 DirectWrite HelloWorld를 참조하세요.

간단한 텍스트 그리기

이 섹션에서는 다음 스크린샷과 같이 DirectWriteDirect2D를 사용하여 단일 형식의 간단한 텍스트를 렌더링하는 방법을 보여줍니다.

단일 형식의

간단한 텍스트를 화면에 그리려면 다음 네 가지 구성 요소가 필요합니다.

  • 렌더링할 문자열입니다.
  • IDWriteTextFormat의 instance.
  • 텍스트를 포함할 영역의 크기입니다.
  • 텍스트를 렌더링할 수 있는 개체입니다. 이 자습서에서는 다음을 수행합니다. Direct2D 렌더링 대상을 사용합니다.

IDWriteTextFormat 인터페이스는 텍스트 서식 지정에 사용되는 글꼴 패밀리 이름, 크기, 두께, 스타일 및 스트레치를 설명하고 로캘 정보를 설명합니다. IDWriteTextFormat 은 다음 속성을 설정하고 가져오는 메서드도 정의합니다.

  • 줄 간격입니다.
  • 레이아웃 상자의 왼쪽 및 오른쪽 가장자리를 기준으로 하는 텍스트 맞춤입니다.
  • 레이아웃 상자의 위쪽과 아래쪽을 기준으로 하는 단락 맞춤입니다.
  • 읽기 방향입니다.
  • 레이아웃 상자를 오버플로하는 텍스트의 텍스트 트리밍 세분성입니다.
  • 증분 탭 정지입니다.
  • 단락 흐름 방향입니다.

IDWriteTextFormat 인터페이스는 이 문서에 설명된 두 프로세스를 모두 사용하는 텍스트를 그리는 데 필요합니다.

IDWriteTextFormat 개체 또는 다른 DirectWrite 개체를 만들려면 IDWriteFactory instance 필요합니다. IDWriteFactory를 사용하여 IDWriteTextFormat 인스턴스 및 기타 DirectWrite 개체를 만듭니다. 팩터리 instance 가져오려면 DWriteCreateFactory 함수를 사용합니다.

1부: DirectWrite 및 Direct2D 리소스를 선언합니다.

이 부분에서는 나중에 텍스트를 만들고 클래스의 프라이빗 데이터 멤버로 표시하는 데 사용할 개체를 선언합니다. DirectWrite 대한 모든 인터페이스, 함수 및 데이터 형식은 dwrite.h 헤더 파일에 선언되고 Direct2D에 대한 인터페이스는 d2d1.h에 선언됩니다. 아직 이 작업을 수행하지 않은 경우 프로젝트에 이러한 헤더를 포함합니다.

  1. 클래스 헤더 파일(SimpleText.h)에서 IDWriteFactoryIDWriteTextFormat 인터페이스에 대한 포인터를 프라이빗 멤버로 선언합니다.

    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    
    
  2. 렌더링할 텍스트 문자열과 문자열의 길이를 저장할 멤버를 선언합니다.

    const wchar_t* wszText_;
    UINT32 cTextLength_;
    
    
  3. Direct2D를 사용하여 텍스트를 렌더링하기 위한 ID2D1Factory, ID2D1HwndRenderTargetID2D1SolidColorBrush 인터페이스에 대한 포인터를 선언합니다.

    ID2D1Factory* pD2DFactory_;
    ID2D1HwndRenderTarget* pRT_;
    ID2D1SolidColorBrush* pBlackBrush_;
    
    

2부: 디바이스 독립적 리소스 만들기

Direct2D 는 디바이스 종속 리소스와 디바이스 독립적 리소스의 두 가지 유형의 리소스를 제공합니다. 디바이스 종속 리소스는 렌더링 디바이스와 연결되며 해당 디바이스가 제거되면 더 이상 작동하지 않습니다. 반면에 디바이스 독립적 리소스는 애플리케이션의 scope 동안 지속될 수 있습니다.

DirectWrite 리소스는 디바이스 독립적입니다.

이 섹션에서는 애플리케이션에서 사용하는 디바이스 독립적 리소스를 만듭니다. 이러한 리소스는 인터페이스의 Release 메서드를 호출하여 해제해야 합니다.

사용되는 리소스 중 일부는 한 번만 만들어야 하며 디바이스에 연결되지 않습니다. 이러한 리소스에 대한 초기화는 클래스를 초기화할 때 호출되는 SimpleText::CreateDeviceIndependentResources 메서드에 배치됩니다.

  1. 클래스 구현 파일(SimpleText.cpp)의 SimpleText::CreateDeviceIndependentResources 메서드 내에서 D2D1CreateFactory 함수를 호출하여 모든 Direct2D 개체에 대한 루트 팩터리 인터페이스인 ID2D1Factory 인터페이스를 만듭니다. 동일한 팩터리를 사용하여 다른 Direct2D 리소스를 인스턴스화합니다.

    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pD2DFactory_
        );
    
    
  2. DWriteCreateFactory 함수를 호출하여 모든 DirectWrite 개체에 대한 루트 팩터리 인터페이스인 IDWriteFactory 인터페이스를 만듭니다. 동일한 팩터리를 사용하여 다른 DirectWrite 리소스를 인스턴스화합니다.

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
    }
    
    
  3. 텍스트 문자열을 초기화하고 길이를 저장합니다.

    wszText_ = L"Hello World using  DirectWrite!";
    cTextLength_ = (UINT32) wcslen(wszText_);
    
    
  4. IDWriteFactory::CreateTextFormat 메서드를 사용하여 IDWriteTextFormat 인터페이스 개체를 만듭니다. IDWriteTextFormat은 텍스트 문자열을 렌더링하는 데 사용할 글꼴, 두께, 늘이기, 스타일 및 로캘을 지정합니다.

    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTextFormat(
            L"Gabriola",                // Font family name.
            NULL,                       // Font collection (NULL sets it to use the system font collection).
            DWRITE_FONT_WEIGHT_REGULAR,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            72.0f,
            L"en-us",
            &pTextFormat_
            );
    }
    
    
  5. IDWriteTextFormat::SetTextAlignmentIDWriteTextFormat::SetParagraphAlignment 메서드를 호출하여 텍스트를 가로 및 세로로 가운데에 맞춥니다.

    // Center align (horizontally) the text.
    if (SUCCEEDED(hr))
    {
        hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
    }
    
    if (SUCCEEDED(hr))
    {
        hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
    }
    
    

이 부분에서는 애플리케이션에서 사용하는 디바이스 독립적 리소스를 초기화했습니다. 다음 부분에서는 디바이스 종속 리소스를 초기화합니다.

3부: Device-Dependent 리소스 만들기

이 부분에서는 텍스트를 렌더링하기 위한 ID2D1HwndRenderTargetID2D1SolidColorBrush 를 만듭니다.

렌더링 대상은 그리기 리소스를 만들고 그리기 명령을 렌더링하는 Direct2D 개체입니다. ID2D1HwndRenderTargetHWND로 렌더링되는 렌더링 대상입니다.

렌더링 대상이 만들 수 있는 그리기 리소스 중 하나는 윤곽선, 채우기 및 텍스트를 그리기 위한 브러시입니다. ID2D1SolidColorBrush는 단색으로 칠합니다.

ID2D1HwndRenderTargetID2D1SolidColorBrush 인터페이스는 모두 생성될 때 렌더링 디바이스에 바인딩되며 디바이스가 유효하지 않은 경우 해제하고 다시 만들어야 합니다.

  1. SimpleText::CreateDeviceResources 메서드 내에서 렌더링 대상 포인터가 NULL인지 여부를 검사. 이 경우 렌더링 영역의 크기를 검색하고 해당 크기의 ID2D1HwndRenderTarget 을 만듭니다. ID2D1HwndRenderTarget을 사용하여 ID2D1SolidColorBrush를 만듭니다.

    RECT rc;
    GetClientRect(hwnd_, &rc);
    
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
    
    if (!pRT_)
    {
        // Create a Direct2D render target.
        hr = pD2DFactory_->CreateHwndRenderTarget(
                D2D1::RenderTargetProperties(),
                D2D1::HwndRenderTargetProperties(
                    hwnd_,
                    size
                    ),
                &pRT_
                );
    
        // Create a black brush.
        if (SUCCEEDED(hr))
        {
            hr = pRT_->CreateSolidColorBrush(
                D2D1::ColorF(D2D1::ColorF::Black),
                &pBlackBrush_
                );
        }
    }
    
    
  2. SimpleText::D iscardDeviceResources 메서드에서 브러시와 렌더링 대상을 모두 해제합니다.

    SafeRelease(&pRT_);
    SafeRelease(&pBlackBrush_);
    
    

렌더링 대상과 브러시를 만들었으므로 이제 이를 사용하여 텍스트를 렌더링할 수 있습니다.

4부: Direct2D DrawText 메서드를 사용하여 텍스트 그리기

  1. 클래스의 SimpleText::D rawText 메서드에서 렌더링 영역의 차원을 검색하여 텍스트 레이아웃의 영역을 정의하고 동일한 차원이 있는 Direct2D 사각형을 만듭니다.

    D2D1_RECT_F layoutRect = D2D1::RectF(
        static_cast<FLOAT>(rc.left) / dpiScaleX_,
        static_cast<FLOAT>(rc.top) / dpiScaleY_,
        static_cast<FLOAT>(rc.right - rc.left) / dpiScaleX_,
        static_cast<FLOAT>(rc.bottom - rc.top) / dpiScaleY_
        );
    
    
  2. ID2D1RenderTarget::D rawText 메서드 및 IDWriteTextFormat 개체를 사용하여 텍스트를 화면에 렌더링합니다. ID2D1RenderTarget::D rawText 메서드는 다음 매개 변수를 사용합니다.

    pRT_->DrawText(
        wszText_,        // The string to render.
        cTextLength_,    // The string's length.
        pTextFormat_,    // The text format.
        layoutRect,       // The region of the window where the text will be rendered.
        pBlackBrush_     // The brush used to draw the text.
        );
    
    

5부: Direct2D를 사용하여 창 콘텐츠 렌더링

페인트 메시지가 수신될 때 Direct2D 를 사용하여 창의 내용을 렌더링하려면 다음을 수행합니다.

  1. 3부에서 구현된 SimpleText::CreateDeviceResources 메서드를 호출하여 디바이스 종속 리소스를 만듭니다.
  2. 렌더링 대상의 ID2D1HwndRenderTarget::BeginDraw 메서드를 호출합니다.
  3. ID2D1HwndRenderTarget::Clear 메서드를 호출하여 렌더링 대상을 지웁니다.
  4. 4부에서 구현된 SimpleText::D rawText 메서드를 호출합니다.
  5. 렌더링 대상의 ID2D1HwndRenderTarget::EndDraw 메서드를 호출합니다.
  6. 필요한 경우 창이 다시 그려질 때 다시 만들 수 있도록 디바이스 종속 리소스를 삭제합니다.
hr = CreateDeviceResources();

if (SUCCEEDED(hr))
{
    pRT_->BeginDraw();

    pRT_->SetTransform(D2D1::IdentityMatrix());

    pRT_->Clear(D2D1::ColorF(D2D1::ColorF::White));

    // Call the DrawText method of this class.
    hr = DrawText();

    if (SUCCEEDED(hr))
    {
        hr = pRT_->EndDraw(
            );
    }
}

if (FAILED(hr))
{
    DiscardDeviceResources();
}

SimpleText 클래스는 SimpleText.h 및 SimpleText.cpp에서 구현됩니다.

여러 서식으로 텍스트 그리기

이 섹션에서는 다음 스크린샷과 같이 DirectWriteDirect2D를 사용하여 여러 형식의 텍스트를 렌더링하는 방법을 보여 줍니다.

스타일, 크기 및 형식이 다른 일부 파트가 있는

이 섹션의 코드는 DirectWrite HelloWorld에서 MultiformattedText 클래스로 구현됩니다. 이전 섹션의 단계를 기반으로 합니다.

여러 형식의 텍스트를 만들려면 이전 섹션에서 도입된 IDWriteTextFormat 인터페이스 외에도 IDWriteTextLayout 인터페이스를 사용합니다. IDWriteTextLayout 인터페이스는 텍스트 블록의 서식 및 레이아웃을 설명합니다. IDWriteTextFormat 개체에 지정된 기본 서식 외에도 IDWriteTextLayout을 사용하여 특정 텍스트 범위에 대한 서식을 변경할 수 있습니다. 여기에는 글꼴 패밀리 이름, 크기, 두께, 스타일, 스트레치, 취소선 및 밑줄이 포함됩니다.

IDWriteTextLayout 은 적중 테스트 메서드도 제공합니다. 이러한 메서드에서 반환된 적중 테스트 메트릭은 IDWriteFactory 인터페이스의 CreateTextLayout 메서드를 사용하여 IDWriteTextLayout 인터페이스 개체 를 만들 때 지정된 레이아웃 상자를 기준으로 합니다.

IDWriteTypography 인터페이스는 선택적 OpenType 입력 체계 기능을 텍스트 레이아웃(예: swashes 및 대체 스타일 텍스트 집합)에 추가하는 데 사용됩니다. IDWriteTypography 인터페이스의 AddFontFeature 메서드를 호출하여 텍스트 레이아웃 내의 특정 텍스트 범위에 입력 기능을 추가할 수 있습니다. 이 메서드는 DWRITE_FONT_FEATURE 구조체를 DWRITE_FONT_FEATURE_TAG 열거형 상수 및 UINT32 실행 매개 변수를 포함하는 매개 변수로 받습니다. 등록된 OpenType 기능 목록은 microsoft.com OpenType 레이아웃 태그 레지스트리 에서 찾을 수 있습니다. 해당하는 DirectWrite 열거형 상수는 DWRITE_FONT_FEATURE_TAG 참조하세요.

1부: IDWriteTextLayout 인터페이스를 만듭니다.

  1. IDWriteTextLayout 인터페이스에 대한 포인터를 MultiformattedText 클래스의 멤버로 선언합니다.

    IDWriteTextLayout* pTextLayout_;
    
    
  2. MultiformattedText::CreateDeviceIndependentResources 메서드의 끝에 CreateTextLayout 메서드를 호출하여 IDWriteTextLayout 인터페이스 개체를 만듭니다. 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.
            );
    }
    
    

2부: IDWriteTextLayout을 사용하여 서식 적용

글꼴 크기, 가중치 및 밑줄과 같은 서식은 IDWriteTextLayout 인터페이스를 사용하여 표시할 텍스트의 부분 문자열에 적용할 수 있습니다.

  1. DWRITE_TEXT_RANGE 선언하고 IDWriteTextLayout::SetFontSize 메서드를 호출하여 "DirectWrite" 부분 문자열 "Di"의 글꼴 크기를 100으로 설정합니다.

    // Format the "DirectWrite" substring to be of font size 100.
    if (SUCCEEDED(hr))
    {
        DWRITE_TEXT_RANGE textRange = {20,        // Start index where "DirectWrite" appears.
                                        6 };      // Length of the substring "Direct" in "DirectWrite".
        hr = pTextLayout_->SetFontSize(100.0f, textRange);
    }
    
  2. IDWriteTextLayout::SetUnderline 메서드를 호출하여 부분 문자열 "DirectWrite"에 밑줄을 긋습니다.

    // Format the word "DWrite" to be underlined.
    if (SUCCEEDED(hr))
    {
    
        DWRITE_TEXT_RANGE textRange = {20,      // Start index where "DirectWrite" appears.
                                       11 };    // Length of the substring "DirectWrite".
        hr = pTextLayout_->SetUnderline(TRUE, textRange);
    }
    
  3. IDWriteTextLayout::SetFontWeight 메서드를 호출하여 부분 문자열 "DirectWrite"에 대해 글꼴 두께를 굵게 설정합니다.

    if (SUCCEEDED(hr))
    {
        // Format the word "DWrite" to be bold.
        DWRITE_TEXT_RANGE textRange = {20,
                                       11 };
        hr = pTextLayout_->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, textRange);
    }
    

3부: IDWriteTypography를 사용하여 입력 체계 기능 추가

  1. IDWriteFactory::CreateTypography 메서드를 호출하여 IDWriteTypography 인터페이스 개체를 선언하고 만듭니다.

    // Declare a typography pointer.
    IDWriteTypography* pTypography = NULL;
    
    // Create a typography interface object.
    if (SUCCEEDED(hr))
    {
        hr = pDWriteFactory_->CreateTypography(&pTypography);
    }
    
    
  2. 스타일 집합 7이 지정된 DWRITE_FONT_FEATURE 개체를 선언하고 IDWriteTypography::AddFontFeature 메서드를 호출하여 글꼴 기능을 추가합니다.

    // Set the stylistic set.
    DWRITE_FONT_FEATURE fontFeature = {DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7,
                                       1};
    if (SUCCEEDED(hr))
    {
        hr = pTypography->AddFontFeature(fontFeature);
    }
    
    
  3. DWRITE_TEXT_RANGE 변수를 선언하고 IDWriteTextLayout::SetTypography 메서드를 호출하고 텍스트 범위를 전달하여 전체 문자열에서 입력 체계를 사용하도록 텍스트 레이아웃을 설정합니다.

    if (SUCCEEDED(hr))
    {
        // Set the typography for the entire string.
        DWRITE_TEXT_RANGE textRange = {0,
                                       cTextLength_};
        hr = pTextLayout_->SetTypography(pTypography, textRange);
    }
    
    
  4. MultiformattedText::OnResize 메서드에서 텍스트 레이아웃 개체의 새 너비와 높이를 설정합니다.

    if (pTextLayout_)
    {
        pTextLayout_->SetMaxWidth(static_cast<FLOAT>(width / dpiScaleX_));
        pTextLayout_->SetMaxHeight(static_cast<FLOAT>(height / dpiScaleY_));
    }
    

4부: Direct2D DrawTextLayout 메서드를 사용하여 텍스트 그리기

IDWriteTextLayout 개체에서 지정한 텍스트 레이아웃 설정으로 텍스트를 그리려면 MultiformattedText::D rawText 메서드의 코드를 변경하여 IDWriteTextLayout::D rawTextLayout을 사용합니다.

  1. D2D1_POINT_2F 변수를 Delcare로 설정하고 창의 왼쪽 위 지점으로 설정합니다.

    D2D1_POINT_2F origin = D2D1::Point2F(
        static_cast<FLOAT>(rc.left / dpiScaleX_),
        static_cast<FLOAT>(rc.top / dpiScaleY_)
        );
    
    
  2. Direct2D 렌더링 대상의 ID2D1RenderTarget::D rawTextLayout 메서드를 호출하고 IDWriteTextLayout 포인터를 전달하여 텍스트를 화면에 그립니다.

    pRT_->DrawTextLayout(
        origin,
        pTextLayout_,
        pBlackBrush_
        );
    
    

MultiformattedText 클래스는 MultiformattedText.h 및 MultiformattedText.cpp에서 구현됩니다.