AddFontMemResourceEx는 DWrite의 CreateTextFormat 등에서 적용되지 않는다.
DWrite의 CreateTextFormat 함수는 두 번째 인자로 fontCollection을 받는데, 이 값이 nullptr이면 시스템 폰트에서 첫 번째 인자로 주는 fontFamilyName을 검색한다.
DWrite에서 시스템 폰트 이외의 폰트를 사용하는 방법은 이 폰트 컬렉션을 만드는 방법이다.
폰트 컬렉션을 만드는 방법은 크게 두 가지로 나눌 수 있는데, 하나는 Windows 10 이상의 환경에서만 사용 가능한 방법과 그 이전의 버전에서 사용 가능한 방법이다.
- 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 파일을 사용한다면 이 과정은 생략해도 된다.
간단한 스텝에 대해 설명하자면,
- ResourceFontContext 객체를 선언한다.
- CreateFontCollection 함수를 호출한다.
첫 번째 인자는 Font Collection Key이고 두 번째 인자는 그 key의 size이다.
여기서 알아둘 점은, 이 key는 리소스 ID 또는 CustomFontFileReference에서 설정한 ID 값이다.
- 세 번째 인자로 넘긴 fontCollection 객체를 활용하여 폰트를 만든다.
이 방법이 귀찮고 어려운 이유는, CustomFontCollection을만들기 위해 필요한 IDWriteFontCollectionLoader 객체를 결국 사용자가 직접 구현을 해 줘야 한다는 점이다.
이러한 문제는 Windows 10이 되면서 매우 간단하게 해결이 되었다.
- Windows 10 이상의 버전에서 사용하는 방법
말도 필요 없을 정도로 간단해졌다.
Windows 10부터 추가된 IDWriteFactory3 객체에FontSet 관련 API가 들어가서, 더는FontCollectionLoader 객체를 직접 만들어줄 필요가 없어졌다.
사실 이 버전의 폰트 추가 방법에 대해서는 MS 공식문서가 잘 되어 있어서 굳이 포스팅할 필요는 없지만, 간단히 소개해보자 한다.
우선 공식 문서 : https://docs.microsoft.com/en-us/windows/desktop/directwrite/custom-font-sets-win10
이번에는 리소스에 저장된 폰트는 설명을 생략한다. 공식 문서의 InMemoryFont 참고.
그리고 이 포스트에서 설명하는 건 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 등의 함수가 있으니 적절히 참고하자.
덧글
지금은 편리하게 쓸수있는 방법이나왔다니 아쉬워 그당시에 이방법이 있었다면 시간을 좀더아낄수있었을텐데말에요ㅋ글잘봤습니다~