[Direct2D/DWrite]설치되지 않은 폰트 설치하지 않고 사용하기 Lu's…〃 Programing。

AddFontMemResourceEx DWrite CreateTextFormat 등에서 적용되지 않는다.

 

DWrite CreateTextFormat 함수는 번째 인자로 fontCollection 받는데, 값이 nullptr이면 시스템 폰트에서 번째 인자로 주는 fontFamilyName 검색한다.

 

DWrite에서 시스템 폰트 이외의 폰트를 사용하는 방법은 폰트 컬렉션을 만드는 방법이다.

 

폰트 컬렉션을 만드는 방법은 크게 가지로 나눌 있는데, 하나는 Windows 10 이상의 환경에서만 사용 가능한 방법과 이전의 버전에서 사용 가능한 방법이다.

 

 

 

  1. Windows 10 이전 버전 호환을 위한 방법

 

Windows 7/8.1에서 사용되는 방법은 Windows 7 Windows SDKSample에 있는데… 지금 찾아보니 페이지가 중국 MS 기술문서 말고는 누가 Github 아카이빙한 말고는 찾겠더라.

 

https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/master/multimedia/DirectWrite/CustomFont

 

예제는 폰트 파일에서 불러오는 아니라 .rc 파일에 있는 폰트를 불러오는 시나리오다. 만약 폰트를 파일에서 불러오고 싶으면 CreateFontFileReference 함수를 써서 reference key 알아낸 이를 사용하여 CreateCustomFontFileReference함수를 호출하여 custom file file reference 만드는 방법이 있다. 만약 rc 파일을 사용한다면 과정은 생략해도 된다.

 

 간단한 스텝에 대해 설명하자면,

 

  1. ResourceFontContext 객체를 선언한다.
     
  2. CreateFontCollection 함수를 호출한다.
    번째 인자는 Font Collection Key이고 번째 인자는 key size이다.

    여기서 알아둘 점은, key 리소스 ID 또는 CustomFontFileReference에서 설정한 ID 값이다.
     
  3. 번째 인자로 넘긴 fontCollection 객체를 활용하여 폰트를 만든다.

 

 

 

방법이 귀찮고 어려운 이유는, CustomFontCollection만들기 위해 필요한 IDWriteFontCollectionLoader 객체를 결국 사용자가 직접 구현을 줘야 한다는 점이다.

 

이러한 문제는 Windows 10 되면서 매우 간단하게 해결이 되었다.

 

 

 

  1. Windows 10 이상의 버전에서 사용하는 방법

 

말도 필요 없을 정도로 간단해졌다.

 

Windows 10부터 추가된 IDWriteFactory3 객체에FontSet 관련 API 들어가서, 더는FontCollectionLoader 객체를 직접 만들어줄 필요가 없어졌다.

 

사실 버전의 폰트 추가 방법에 대해서는 MS 공식문서가 되어 있어서 굳이 포스팅할 필요는 없지만, 간단히 소개해보자 한다.

 

우선 공식 문서 : https://docs.microsoft.com/en-us/windows/desktop/directwrite/custom-font-sets-win10

 

이번에는 리소스에 저장된 폰트는 설명을 생략한다. 공식 문서의 InMemoryFont 참고.

https://docs.microsoft.com/en-us/windows/desktop/directwrite/custom-font-sets-win10#creating-a-custom-font-set-using-font-data-loaded-into-memory

 

 

그리고 포스트에서 설명하는 IDWriteFactory5 객체에 대해서이다. IDWriteFactory3 객체에 대해서는 공식 문서를 참고하기 바란다.

 

가지 필요한 클래스들을 열거해보겠다.


IDWriteFontFile

FontFileReference 얻기 위해 필요한 객체

IDWriteFontSetBuilder1

FontFile 추가하여 FontSet 만드는 Builder 객체

IDWriteFontSet

FontCollection 바꿔먹을

 

최종적으로 FontCollection 만들어지면 개의 객체는 유지되지 않아도 괜찮다. , InMemoryFont 위한 IDWriteInMemoryFontFileLoader 객체의 경우에는 따로 가지고 있다가 객체 소멸 UnregisterFontFileLoader 호출해야한다.

 

 

 

아까 Windows 7/8.1과는 다르게 정말 편해졌다.

 

  ComPtr<IDWriteFontFile> fontFileReference;

 dwFactory->CreateFontFileReference(L"MyFont.ttf", nullptr, &fontFileReference);
 
 ComPtr<IDWriteFontSetBuilder1> fontSetBuilder;
  dwFactory->CreateFontSetBuilder(&fontSetBuilder);
 
  fontSetBuilder->AddFontFile(fontFileReference.Get());
 
 ComPtr<IDWriteFontSet> customFontSet;
  fontSetBuilder->CreateFontSet(&customFontSet);
 
  dwFactory->CreateFontCollectionFromFontSet(

       customFontSet.Get()

    , &m_pdwFontCollection

    );

 

 

 

+) 추가

 

이렇게 추가한 폰트의 이름을 모를 있다. 예를 들어 "TFont"인줄 알았는데 "Test Font"라고 입력해야만 해당 폰트를 찾을 수도 있고. 이럴 때를 위한 폰트 이름을 찾는 방법이다.

 

여기서 폰트이름을 TCHAR[65] 설정했는데, 사실 이건 내가 몰라서 이렇게 지은 것이다. 수도 있다. 적절히 정하자.

 

원리는 단순하다. 아까 만든 FontCollection에서 FontFamily 얻어내 이름들을 얻어올 것이다.

 

  ComPtr<IDWriteFontFamily> fontFamily;
 ComPtr<IDWriteLocalizedStrings> localizedFontName;
 TCHAR c_styleFontName[65];

  m_pdwFontCollection->GetFontFamily(0, &fontFamily);
  fontFamily->GetFamilyNames(&localizedFontName);
  localizedFontName->GetString(0, c_styleFontName, 65);

 

만약 여러 개의 폰트를 FontCollection 추가했다면, FontCollection GetCount 등의 함수가 있으니 적절히 참고하자.

 




덧글

  • ㄴㄱㄴ 2020/05/03 17:10 # 삭제 답글

    안녕하세요 웹서핑하다 옛날생각나서 댓글 다네요 예전에 2D 게임엔진만든다고 삽질할때 Direct2D 랑 Directwrite 쓰려다 외부폰트따로불러오는게 넘어려워서 걍 DirectX9 3D로 빽도했던 기억이 나네요 그당시 구글링하니까 커스텀폰트컬렉션이니 스왑체인이니 엄청 까다롭고 긴 코드들 github서 보고 난아직도멀었구나하고 좌절했던 기억이나네요 ㅎ

    지금은 편리하게 쓸수있는 방법이나왔다니 아쉬워 그당시에 이방법이 있었다면 시간을 좀더아낄수있었을텐데말에요ㅋ글잘봤습니다~
댓글 입력 영역