자습서: DirectWrite 시작
이 문서에서는 DirectWrite 및 Direct2D를 사용하여 단일 형식을 포함하는 간단한 텍스트를 만든 다음 여러 서식이 포함된 텍스트를 만드는 방법을 보여 줍니다.
이 자습서에는 다음 부분이 포함되어 있습니다.
소스 코드
이 개요에 표시된 소스 코드는 DirectWrite 헬로 월드 샘플에서 가져옵니다. 각 파트는 별도의 클래스(SimpleText 및 MultiformattedText)에서 구현되며 별도의 자식 창에 표시됩니다. 각 클래스는 Microsoft Win32 창을 나타냅니다. WndProc 메서드 외에도 각 클래스에는 다음 메서드가 포함됩니다.
기능 | Description |
---|---|
CreateDeviceIndependentResources | 디바이스 독립적 리소스를 만들어 어디서나 재사용할 수 있습니다. |
DiscardDeviceIndependentResources | 더 이상 필요하지 않은 디바이스 독립적 리소스를 해제합니다. |
CreateDeviceResources | 특정 디바이스에 연결된 브러시 및 렌더링 대상과 같은 리소스를 만듭니다. |
DiscardDeviceResources | 더 이상 필요하지 않은 디바이스 종속 리소스를 해제합니다. |
DrawD2DContent | Direct2D를 사용하여 화면에 렌더링합니다. |
Drawtext | Direct2D를 사용하여 텍스트 문자열을 그립니다. |
Onresize | 창 크기가 변경되면 Direct2D 렌더링 대상의 크기를 조정합니다. |
제공된 샘플을 사용하거나 다음 지침을 사용하여 사용자 고유의 Win32 애플리케이션에 DirectWrite 및 Direct2D를 추가할 수 있습니다. 샘플 및 관련 프로젝트 파일에 대한 자세한 내용은 DirectWrite HelloWorld를 참조하세요.
간단한 텍스트 그리기
이 섹션에서는 다음 스크린샷과 같이 DirectWrite 및 Direct2D를 사용하여 단일 형식의 간단한 텍스트를 렌더링하는 방법을 보여줍니다.
간단한 텍스트를 화면에 그리려면 다음 네 가지 구성 요소가 필요합니다.
- 렌더링할 문자열입니다.
- IDWriteTextFormat의 instance.
- 텍스트를 포함할 영역의 크기입니다.
- 텍스트를 렌더링할 수 있는 개체입니다. 이 자습서에서는 다음을 수행합니다. Direct2D 렌더링 대상을 사용합니다.
IDWriteTextFormat 인터페이스는 텍스트 서식 지정에 사용되는 글꼴 패밀리 이름, 크기, 두께, 스타일 및 스트레치를 설명하고 로캘 정보를 설명합니다. IDWriteTextFormat 은 다음 속성을 설정하고 가져오는 메서드도 정의합니다.
- 줄 간격입니다.
- 레이아웃 상자의 왼쪽 및 오른쪽 가장자리를 기준으로 하는 텍스트 맞춤입니다.
- 레이아웃 상자의 위쪽과 아래쪽을 기준으로 하는 단락 맞춤입니다.
- 읽기 방향입니다.
- 레이아웃 상자를 오버플로하는 텍스트의 텍스트 트리밍 세분성입니다.
- 증분 탭 정지입니다.
- 단락 흐름 방향입니다.
IDWriteTextFormat 인터페이스는 이 문서에 설명된 두 프로세스를 모두 사용하는 텍스트를 그리는 데 필요합니다.
IDWriteTextFormat 개체 또는 다른 DirectWrite 개체를 만들려면 IDWriteFactory instance 필요합니다. IDWriteFactory를 사용하여 IDWriteTextFormat 인스턴스 및 기타 DirectWrite 개체를 만듭니다. 팩터리 instance 가져오려면 DWriteCreateFactory 함수를 사용합니다.
1부: DirectWrite 및 Direct2D 리소스를 선언합니다.
이 부분에서는 나중에 텍스트를 만들고 클래스의 프라이빗 데이터 멤버로 표시하는 데 사용할 개체를 선언합니다. DirectWrite 대한 모든 인터페이스, 함수 및 데이터 형식은 dwrite.h 헤더 파일에 선언되고 Direct2D에 대한 인터페이스는 d2d1.h에 선언됩니다. 아직 이 작업을 수행하지 않은 경우 프로젝트에 이러한 헤더를 포함합니다.
클래스 헤더 파일(SimpleText.h)에서 IDWriteFactory 및 IDWriteTextFormat 인터페이스에 대한 포인터를 프라이빗 멤버로 선언합니다.
IDWriteFactory* pDWriteFactory_; IDWriteTextFormat* pTextFormat_;
렌더링할 텍스트 문자열과 문자열의 길이를 저장할 멤버를 선언합니다.
const wchar_t* wszText_; UINT32 cTextLength_;
Direct2D를 사용하여 텍스트를 렌더링하기 위한 ID2D1Factory, ID2D1HwndRenderTarget 및 ID2D1SolidColorBrush 인터페이스에 대한 포인터를 선언합니다.
ID2D1Factory* pD2DFactory_; ID2D1HwndRenderTarget* pRT_; ID2D1SolidColorBrush* pBlackBrush_;
2부: 디바이스 독립적 리소스 만들기
Direct2D 는 디바이스 종속 리소스와 디바이스 독립적 리소스의 두 가지 유형의 리소스를 제공합니다. 디바이스 종속 리소스는 렌더링 디바이스와 연결되며 해당 디바이스가 제거되면 더 이상 작동하지 않습니다. 반면에 디바이스 독립적 리소스는 애플리케이션의 scope 동안 지속될 수 있습니다.
DirectWrite 리소스는 디바이스 독립적입니다.
이 섹션에서는 애플리케이션에서 사용하는 디바이스 독립적 리소스를 만듭니다. 이러한 리소스는 인터페이스의 Release 메서드를 호출하여 해제해야 합니다.
사용되는 리소스 중 일부는 한 번만 만들어야 하며 디바이스에 연결되지 않습니다. 이러한 리소스에 대한 초기화는 클래스를 초기화할 때 호출되는 SimpleText::CreateDeviceIndependentResources 메서드에 배치됩니다.
클래스 구현 파일(SimpleText.cpp)의 SimpleText::CreateDeviceIndependentResources 메서드 내에서 D2D1CreateFactory 함수를 호출하여 모든 Direct2D 개체에 대한 루트 팩터리 인터페이스인 ID2D1Factory 인터페이스를 만듭니다. 동일한 팩터리를 사용하여 다른 Direct2D 리소스를 인스턴스화합니다.
hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory_ );
DWriteCreateFactory 함수를 호출하여 모든 DirectWrite 개체에 대한 루트 팩터리 인터페이스인 IDWriteFactory 인터페이스를 만듭니다. 동일한 팩터리를 사용하여 다른 DirectWrite 리소스를 인스턴스화합니다.
if (SUCCEEDED(hr)) { hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWriteFactory_) ); }
텍스트 문자열을 초기화하고 길이를 저장합니다.
wszText_ = L"Hello World using DirectWrite!"; cTextLength_ = (UINT32) wcslen(wszText_);
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_ ); }
IDWriteTextFormat::SetTextAlignment 및 IDWriteTextFormat::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 리소스 만들기
이 부분에서는 텍스트를 렌더링하기 위한 ID2D1HwndRenderTarget 및 ID2D1SolidColorBrush 를 만듭니다.
렌더링 대상은 그리기 리소스를 만들고 그리기 명령을 렌더링하는 Direct2D 개체입니다. ID2D1HwndRenderTarget은 HWND로 렌더링되는 렌더링 대상입니다.
렌더링 대상이 만들 수 있는 그리기 리소스 중 하나는 윤곽선, 채우기 및 텍스트를 그리기 위한 브러시입니다. ID2D1SolidColorBrush는 단색으로 칠합니다.
ID2D1HwndRenderTarget 및 ID2D1SolidColorBrush 인터페이스는 모두 생성될 때 렌더링 디바이스에 바인딩되며 디바이스가 유효하지 않은 경우 해제하고 다시 만들어야 합니다.
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_ ); } }
SimpleText::D iscardDeviceResources 메서드에서 브러시와 렌더링 대상을 모두 해제합니다.
SafeRelease(&pRT_); SafeRelease(&pBlackBrush_);
렌더링 대상과 브러시를 만들었으므로 이제 이를 사용하여 텍스트를 렌더링할 수 있습니다.
4부: Direct2D DrawText 메서드를 사용하여 텍스트 그리기
클래스의 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_ );
ID2D1RenderTarget::D rawText 메서드 및 IDWriteTextFormat 개체를 사용하여 텍스트를 화면에 렌더링합니다. ID2D1RenderTarget::D rawText 메서드는 다음 매개 변수를 사용합니다.
- 렌더링할 문자열입니다.
- IDWriteTextFormat 인터페이스에 대한 포인터입니다.
- Direct2D 레이아웃 사각형입니다.
- ID2D1Brush를 노출하는 인터페이스에 대한 포인터입니다.
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 를 사용하여 창의 내용을 렌더링하려면 다음을 수행합니다.
- 3부에서 구현된 SimpleText::CreateDeviceResources 메서드를 호출하여 디바이스 종속 리소스를 만듭니다.
- 렌더링 대상의 ID2D1HwndRenderTarget::BeginDraw 메서드를 호출합니다.
- ID2D1HwndRenderTarget::Clear 메서드를 호출하여 렌더링 대상을 지웁니다.
- 4부에서 구현된 SimpleText::D rawText 메서드를 호출합니다.
- 렌더링 대상의 ID2D1HwndRenderTarget::EndDraw 메서드를 호출합니다.
- 필요한 경우 창이 다시 그려질 때 다시 만들 수 있도록 디바이스 종속 리소스를 삭제합니다.
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에서 구현됩니다.
여러 서식으로 텍스트 그리기
이 섹션에서는 다음 스크린샷과 같이 DirectWrite 및 Direct2D를 사용하여 여러 형식의 텍스트를 렌더링하는 방법을 보여 줍니다.
이 섹션의 코드는 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 인터페이스를 만듭니다.
IDWriteTextLayout 인터페이스에 대한 포인터를 MultiformattedText 클래스의 멤버로 선언합니다.
IDWriteTextLayout* pTextLayout_;
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 인터페이스를 사용하여 표시할 텍스트의 부분 문자열에 적용할 수 있습니다.
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); }
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); }
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를 사용하여 입력 체계 기능 추가
IDWriteFactory::CreateTypography 메서드를 호출하여 IDWriteTypography 인터페이스 개체를 선언하고 만듭니다.
// Declare a typography pointer. IDWriteTypography* pTypography = NULL; // Create a typography interface object. if (SUCCEEDED(hr)) { hr = pDWriteFactory_->CreateTypography(&pTypography); }
스타일 집합 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); }
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); }
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을 사용합니다.
D2D1_POINT_2F 변수를 Delcare로 설정하고 창의 왼쪽 위 지점으로 설정합니다.
D2D1_POINT_2F origin = D2D1::Point2F( static_cast<FLOAT>(rc.left / dpiScaleX_), static_cast<FLOAT>(rc.top / dpiScaleY_) );
Direct2D 렌더링 대상의 ID2D1RenderTarget::D rawTextLayout 메서드를 호출하고 IDWriteTextLayout 포인터를 전달하여 텍스트를 화면에 그립니다.
pRT_->DrawTextLayout( origin, pTextLayout_, pBlackBrush_ );
MultiformattedText 클래스는 MultiformattedText.h 및 MultiformattedText.cpp에서 구현됩니다.