カスタム フォント セット
このトピックでは、アプリでカスタム フォントを使用するさまざまな方法について説明します。
はじめに
ほとんどの場合、アプリはシステムにローカルにインストールされているフォントを使用します。 DirectWriteは、IDWriteFactory3::GetSystemFontSet メソッドまたは IDWriteFactory::GetSystemFontCollection メソッドを使用して、これらのフォントにアクセスできます。 場合によっては、アプリでは、Windows 10の一部として含まれているが、現在のシステムにインストールされていないフォントを使用することもできます。 このようなフォントは、 GetSystemFontSet メソッドを使用するか、includeDownloadableFonts を TRUE に設定して IDWriteFactory3::GetSystemFontCollection を呼び出すことによって、Windows フォント サービスからアクセスできます。
ただし、一部のアプリケーション シナリオでは、システムにインストールされておらず、Windows フォント サービスによって提供されていないフォントをアプリで使用する必要があります。 このようなシナリオの例を次に示します。
- フォントは、アプリ バイナリ内のリソースとして埋め込まれます。
- フォント ファイルはアプリ パッケージ内にバンドルされ、アプリのインストール フォルダーの下のディスクに格納されます。
- アプリは、ユーザー指定のフォント ファイルを読み込む必要があるフォント開発ツールです。
- フォントは、アプリで表示または編集できるドキュメント ファイルに埋め込まれます。
- アプリは、パブリック Web フォント サービスから取得したフォントを使用します。
- アプリは、プライベート ネットワーク プロトコルを介してストリーミングされたフォント データを使用します。
DirectWriteでは、これらのシナリオや他の同様のシナリオでカスタム フォントを操作するための API が提供されます。 カスタム フォント データは、ローカル ファイル システム内のファイルから取得される場合があります。HTTP を使用してアクセスされたリモートのクラウドベースのソースから。または、メモリ バッファーに読み込まれた後の任意のソースから。
Note
DirectWriteは Windows 7 以降、カスタム フォントを操作するための API を提供してきましたが、新しい API はWindows 10に追加され、Windows 10 Creators Update (プレビュー ビルド 15021 以降) に追加され、いくつかのシナリオを簡単に実装できます。 このトピックでは、ウィンドウ 10 で使用できる API について説明します。 以前のバージョンの Windows で動作する必要があるアプリケーションについては、「 カスタム フォント コレクション (Windows 7/8)」を参照してください。
API の概要
このトピックでは、次の API によって提供される機能に焦点を当てています。
- IDWriteFontSet インターフェイス
- IDWriteFontSetBuilder インターフェイス
- IDWriteFontSetBuilder1 インターフェイス
- IDWriteFontFaceReference インターフェイス
- IDWriteFontFile インターフェイス
- IDWriteFactory::CreateFontFileReference メソッド
- IDWriteFactory::CreateCustomFontFileReference メソッド
- IDWriteFactory3::CreateFontFaceReference メソッド
- DWRITE_FONT_PROPERTY 構造体
- DWRITE_FONT_PROPERTY_ID 列挙
- IDWriteFontFileLoader インターフェイス
- IDWriteFactory::RegisterFontFileLoader メソッド
- IDWriteFactory::UnregisterFontFileLoader メソッド
- IDWriteFactory5::CreateInMemoryFontFileLoader メソッド
- IDWriteInMemoryFontFileLoader インターフェイス
- IDWriteFactory5::CreateHttpFontFileLoader メソッド
- IDWriteRemoteFontFileLoader インターフェイス
- IDWriteFontDownloadQueue インターフェイス
- IDWriteFontDownloadListener インターフェイス
- IDWriteFontFileStream インターフェイス
- IDWriteRemoteFontFileStream インターフェイス
- IDWriteAsyncResult インターフェイス
- IDWriteFactory5::AnalyzeContainerType メソッド
- IDWriteFactory5::UnpackFontFile メソッド
主要な概念
カスタム フォントを操作するためのDirectWrite API を理解するには、これらの API の基になる概念モデルを理解しておくと役立ちます。 主な概念については、こちらを参照してください。
DirectWriteが実際のテキスト レイアウトまたはレンダリングを行う場合は、実際のフォント データにアクセスする必要があります。 フォントフェイスオブジェクトは、ローカルシステムに存在する必要がある実際のフォントデータを保持します。 ただし、特定のフォントの可用性のチェックやユーザーへのフォントの選択の提示など、他の操作では、実際のフォント データ自体ではなく、特定のフォントへの参照が必要です。 DirectWriteでは、フォントの顔参照オブジェクトには、フォントの検索とインスタンス化に必要な情報だけが保持されます。 フォントの顔参照は実際のデータを保持しないため、DirectWriteは、実際のデータがリモート ネットワークの場所にあるフォントの顔参照と、実際のデータがローカルである場合に対処できます。
フォント セットは、フォントを参照したり、ファミリ名やフォントの太さ値などの他のフォントと比較したりするために使用できる、特定の基本的な情報プロパティと共に、フォントの顔参照のセットです。 さまざまなフォントの実際のデータはローカルであるか、すべてリモートであるか、または混在している可能性があります。
フォント セットを使用して、対応するフォント コレクション オブジェクトを取得できます。 詳細については、以下の「フォント セットとフォント コレクション」を参照してください。
IDWriteFontSet インターフェイスは、ファミリ名やフォントの太さなどのプロパティ値、または特定のプロパティ値に一致するフォント面参照のクエリを実行できるメソッドを提供します。 特定の選択範囲にフィルター処理した後、 IDWriteFontFaceReference インターフェイスのインスタンスを取得し、(実際のフォント データが現在リモートの場合) ダウンロード用のメソッドを使用して、レイアウトとレンダリングに使用できる対応する IDWriteFontFace3 オブジェクトを取得できます。
IDWriteFontFile インターフェイスは、各フォントの顔またはフォントの顔参照の基になります。 これはフォント ファイルの場所を表し、フォント ファイル ローダーとフォント ファイル キーの 2 つのコンポーネントがあります。 フォント ファイル ローダー (IDWriteFontFileLoader) は、必要に応じてファイルを開くために使用され、データを含むストリーム (IDWriteFontFileStream) を返します。 ローダーによっては、ローカル ファイル パス、リモート URL、またはメモリ バッファーにデータが配置される場合があります。 キーは、ローダー コンテキスト内でファイルを一意に識別するローダー定義値です。これにより、ローダーはデータを見つけてストリームを作成できます。
カスタム フォントは、カスタム フォント セットに簡単に追加できます。カスタム フォント セットは、フォント ピッカー ユーザー インターフェイスの作成などの目的で、フォント情報のフィルター処理や整理に使用できます。 フォント セットを使用して、IDWriteTextFormat や IDWriteTextLayout などの上位レベルの API で使用するフォント コレクションを作成することもできます。 IDWriteFontSetBuilder インターフェイスを使用して、いくつかのカスタム フォントを含むカスタム フォント セットを作成できます。 また、カスタム フォントとシステム提供のフォントを混在させるカスタム フォント セットを作成するためにも使用できます。または、実際のデータの異なるソース (ローカル ストレージ、リモート URL、メモリ) とフォントを混在させるもの。
前述のように、フォントの顔参照はリモート ソースのフォント データを参照する場合がありますが、レイアウトとレンダリングに使用できるフォントフェイス オブジェクトを取得するには、データをローカルにする必要があります。 リモート データのダウンロードは、フォント ダウンロード キューによって処理されます。 アプリは IDWriteFontDownloadQueue インターフェイスを使用して、ダウンロード プロセスを開始するためのリモート フォントのダウンロード要求をエンキューし、 IDWriteFontDownloadListener オブジェクトを登録して、ダウンロード プロセスが完了したときにアクションを実行できます。
ここで説明するインターフェイスのほとんどは、DirectWriteシステム実装を提供します。 1 つの例外は、リモート フォントがローカルにダウンロードされたときにアプリ固有のアクションを実行するためにアプリが実装する IDWriteFontDownloadListener インターフェイスです。 アプリには、特定の他のインターフェイスに独自のカスタム実装を提供する理由がある場合がありますが、これは特定のより高度なシナリオでのみ必要になります。 たとえば、アプリでは、WOFF2 コンテナー形式を使用するローカル ストレージ内のフォント ファイルを処理するために 、IDWriteFontFileLoader インターフェイスのカスタム実装を提供する必要があります。 その他の詳細については、以下で説明します。
フォントとフォント ファイルの形式
理解するのに役立つもう 1 つの重要な概念は、個々のフォントフェイスとそれらを含むフォント ファイルの関係です。 1 つのフォントを含む OpenType フォント ファイル (.ttf または .otf) の考え方はよく知られています。 ただし、OpenType フォント形式では、複数のフォントを含む 1 つのファイルである OpenType Font Collection (.ttc または .otc) も使用できます。 OpenType コレクション ファイルは、多くの場合、密接に関連し、特定のフォント データに同じ値を持つ大きなフォントに使用されます。1 つのファイルでフォントを組み合わせることで、一般的なデータを複製解除できます。 このため、フォント面またはフォント面参照は、フォント ファイル (または同等のデータ ソース) を参照するだけでなく、ファイルがコレクション ファイルである可能性がある一般的なケースでは、そのファイル内のフォント インデックスも指定する必要があります。
Web で使用されるフォントの場合、フォント データは多くの場合、特定のコンテナー形式 (WOFF または WOFF2) にパックされます。これにより、フォント データの圧縮と、著作権侵害やフォント ライセンス違反に対する何らかのレベルの保護が提供されます。 機能的には、WOFF または WOFF2 ファイルは OpenType フォントまたはフォント コレクション ファイルと同じですが、データを使用する前にアンパックが必要な別の形式でエンコードされます。
特定のDirectWrite API は個々のフォント面を扱う場合があり、他の API は複数の顔を含む OpenType Collection ファイルを含むファイルを処理できます。 同様に、一部の API では未加工の OpenType 形式のデータのみが扱われますが、他の API はパックされた WOFF および WOFF2 コンテナー形式を処理できます。 これらの詳細については、以下の説明で説明します。
フォント セットとフォント コレクション
一部のアプリケーションは、 IDWriteFontCollection インターフェイスを使用してフォントを操作するように実装できます。 フォント コレクションとフォント セットの間には直接の対応があります。 それぞれ同じフォントを保持できますが、異なるorganizationで表示されます。 任意のフォント コレクションから、対応するフォント セットを取得できます。また、その逆も可能です。
多数のカスタム フォントを操作する場合は、フォント セット ビルダー インターフェイスを使用してカスタム フォント セットを作成し、フォント セットの作成後にフォント コレクションを取得するのが最も簡単です。 カスタム フォント セットを作成するプロセスについて、以下で詳しく説明します。 フォント セットから IDWriteFontCollection1 インターフェイスを取得するには、 IDWriteFactory3::CreateFontCollectionFromFontSet メソッドが使用されます。
アプリにコレクション オブジェクトがあり、対応するフォント セットを取得する必要がある場合は、 IDWriteFontCollection1::GetFontSet メソッドを使用してこれを行うことができます。
一般的なシナリオ
このセクションでは、カスタム フォント セットに関連する最も一般的なシナリオについて説明します。
- ローカル ファイル システムのパスで任意のフォントを使用してカスタム フォント セットを作成する。
- ローカル ファイル システムに格納されている既知のフォント (おそらくアプリにバンドルされている) を使用してカスタム フォント セットを作成する。
- Web 上の既知のリモート フォントを使用してカスタム フォント セットを作成する。
- メモリに読み込まれたフォント データを使用してカスタム フォント セットを作成する。
これらのシナリオの完全な実装については、「カスタム フォント セットのDirectWriteサンプル」を参照してください。 このサンプルでは、WOFF または WOFF2 コンテナー形式でパックされたフォント データを処理するためのもう 1 つの高度なシナリオも示しています。これについては、以下で説明します。
ローカル ファイル システムで任意のフォントを使用してフォント セットを作成する
ローカル ストレージ内の任意のフォント ファイル セットを処理する場合、 IDWriteFontSetBuilder1::AddFontFile メソッドは便利です。これは、1 回の呼び出しで、OpenType フォント コレクション ファイル内のすべてのフォント面と、OpenType 変数フォントのすべてのインスタンスを処理できるためです。 これは、Windows 10 Creators Update (プレビュー ビルド 15021 以降) で使用でき、使用可能な場合は常にお勧めします。
このメソッドを使用するには、次のプロセスを使用します。
- 1. まず 、IDWriteFactory5 インターフェイスを作成します。
- ローカル ファイル システムのフォント ファイルごとに、それを参照する IDWriteFontFile を作成します。
- すべてのファイルがフォント セット ビルダーに追加されたら、カスタム フォント セットを作成できます。
IDWriteFactory5* pDWriteFactory;
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory5),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
2. ファクトリを使用して IDWriteFontSetBuilder1 インターフェイスを取得します。
IDWriteFontSetBuilder1* pFontSetBuilder;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder);
}
IDWriteFontFile* pFontFile;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile);
}
4. AddFontFile メソッドを使用して、IDWriteFontFile オブジェクトをフォント セット ビルダーに追加します。
hr = pFontSetBuilder->AddFontFile(pFontFile);
CreateFontFileReference の呼び出しで指定されたファイル パスが、サポートされている OpenType ファイル以外のファイルを参照している場合、AddFontFile の呼び出しはエラー DWRITE_E_FILEFORMATを返します。
IDWriteFontSet* pFontSet;
hr = pFontSetBuilder->CreateFontSet(&pFontSet);
Windows 10 Creators Updateより前のバージョンWindows 10でアプリを実行する必要がある場合、AddFontFile メソッドは使用できません。 可用性を検出するには、 IDWriteFactory3 インターフェイスを作成し、QueryInterface を使用して IDWriteFactory5 インターフェイスを取得します。これが成功した場合は、 IDWriteFontSetBuilder1 インターフェイスと AddFontFile メソッドも使用できます。
AddFontFile メソッドを使用できない場合は、 IDWriteFontSetBuilder::AddFontFaceReference メソッドを使用して個々のフォント面を追加する必要があります。 複数の顔を含む OpenType Font Collection ファイルを使用できるようにするには、 IDWriteFontFile::Analyze メソッドを使用して、ファイル内に含まれる顔の数を決定できます。 このプロセスは次のとおりです。
- 1. まず 、IDWriteFactory3 インターフェイスを作成します。
- ファクトリを使用して IDWriteFontSetBuilder インターフェイスを 取得します。
- フォント ファイルごとに、上記のように IDWriteFontFile を作成します。
- すべての面がフォント セット ビルダーに追加されたら、上記のようにカスタム フォント セットを作成します。
IDWriteFactory3* pDWriteFactory;
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory5),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
IDWriteFontSetBuilder* pFontSetBuilder;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder);
}
IDWriteFontFile* pFontFile;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile);
}
ファイルをフォント セット ビルダーに直接追加する代わりに、顔の数を決定し、個々の IDWriteFontFaceReference オブジェクトを作成する必要があります。
4. Analyze メソッドを使用して、ファイル内の顔の数を取得します。
BOOL isSupported;
DWRITE_FONT_FILE_TYPE fileType;
UINT32 numberOfFonts;
hr = pFontFile->Analyze(&isSupported, &fileType, /* face type */ nullptr, &numberOfFonts);
Analyze メソッドでは、isSupported パラメーターと fileType パラメーターの値も設定されます。 ファイルがサポートされている形式でない場合、isSupported は FALSE になり、ファイルの無視などの適切なアクションを実行できます。
5. numberOfFonts パラメーターに設定されているフォントの数をループします。 ループ内で、ファイル/インデックスペアごとに IDWriteFontFaceReference を作成し、フォント セット ビルダーに追加します。
for (uint32_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++)
{
IDWriteFontFaceReference* pFontFaceReference;
hr = pDWriteFactory->CreateFontFaceReference(pFontFile, fontIndex, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
if (SUCCEEDED(hr))
{
hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference);
}
}
アプリは、Windows 10 Creators Updateで実行するときに推奨される AddFontFile メソッドを使用するように設計できますが、以前のバージョンで実行する場合は AddFontFaceReference メソッドを使用するようにフォールバックWindows 10。 前述のように IDWriteFactory5 インターフェイスの可用性をテストし、それに応じて分岐します。 この方法については、「カスタム フォント セットのDirectWriteサンプル」を参照してください。
ローカル ファイル システムで既知のフォントを使用してフォント セットを作成する
前述のように、フォント セット内の各フォントフェイス参照は、ファミリ名やフォントの太さなどの特定の情報プロパティに関連付けられます。 上記の API 呼び出しを使用してカスタム フォントをフォント セット ビルダーに追加すると、これらの情報プロパティは実際のフォント データから直接取得され、フォントの追加時に読み取られます。 ただし、状況によっては、アプリにフォントに関する別の情報ソースがある場合は、これらのプロパティに独自のカスタム値を指定することをお勧めします。
これがどのように役立つのかの例として、アプリで特定のユーザー インターフェイス要素を表示するために使用されるフォントがアプリにバンドルされているものとします。 新しいアプリ バージョンなど、これらの要素にアプリが使用する特定のフォントを変更する必要がある場合があります。 アプリで特定のフォントへの参照がエンコードされている場合、あるフォントを別のフォントに置き換える場合は、それらの参照をすべて変更する必要があります。 代わりに、アプリでカスタム プロパティを使用して、レンダリングされる要素またはテキストの種類に基づいて機能エイリアスを割り当てる場合は、各エイリアスを 1 か所で特定のフォントにマップし、フォントが作成および操作されるすべてのコンテキストでエイリアスを使用します。その後、1 つのフォントを別のフォントに置き換えるだけで、エイリアスが特定のフォントにマップされる場所を変更するだけで済みます。
情報プロパティのカスタム値は、 IDWriteFontSetBuilder::AddFontFaceReference メソッドが呼び出されたときに割り当てることができます。 これを行う方法は次のとおりです。これは、任意のWindows 10バージョンで使用できます。
上に示すように、まず IDWriteFactory3 インターフェイスと IDWriteFontSet インターフェイスを取得します。 追加するカスタム フォント面ごとに、上に示すように IDWriteFontFaceReference を作成します。 これをフォント セット ビルダー (上記の手順 5 のループ内) に追加する前に、アプリは使用するカスタム プロパティ値を定義します。
カスタム プロパティ値のセットは、 DWRITE_FONT_PROPERTY 構造体の配列を使用して定義されます。 これらのそれぞれが、 DWRITE_FONT_PROPERTY_ID 列挙型から特定のプロパティと、使用される対応するプロパティ値を識別します。
すべてのプロパティ値が文字列として割り当てられることに注意してください。 後でユーザーに表示される可能性がある場合は、異なる言語の特定のプロパティの代替値を設定できますが、これは必須ではありません。 また、カスタム プロパティ値がアプリによって設定されている場合は、指定された値のみが Font セット内で使用されることに注意してください。DirectWriteは、フォント セットで使用される情報プロパティの値をフォントから直接派生させるわけではありません。
次の例では、ファミリ名、フル ネーム、フォントの太さの 3 つの情報プロパティのカスタム値を定義します。
DWRITE_FONT_PROPERTY props[] =
{
{ DWRITE_FONT_PROPERTY_ID_FAMILY_NAME, L"My Icon Font", L"en-US" },
{ DWRITE_FONT_PROPERTY_ID_FULL_NAME, L"My Icon Font", L"en-US" },
{ DWRITE_FONT_PROPERTY_ID_WEIGHT, L"400", nullptr }
};
フォントのプロパティ値の目的の配列を定義した後、AddFontFaceRefence を呼び出し、プロパティ配列とフォント面参照を渡します。
hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference, props, ARRAYSIZE(props));
すべてのカスタム フォントフェイスがフォント セット ビルダーに追加され、そのカスタム プロパティと共に、上記のようにカスタム フォント セットが作成されます。
Web 上の既知のリモート フォントを使用してカスタム フォント セットを作成する
カスタム プロパティは、リモート フォントを操作するために重要です。 各フォントの顔参照には、フォントを特徴付け、他のフォントと区別するための情報プロパティが必要です。 リモート フォントのフォント データはローカルではないため、DirectWriteはフォント データからプロパティを直接派生させることはできません。 そのため、リモート フォントをフォント セット ビルダーに追加する場合は、プロパティを明示的に指定する必要があります。
リモート フォントをフォント セットに追加するための API 呼び出しのシーケンスは、前のシナリオで説明したシーケンスと似ています。 ただし、フォント データはリモートであるため、実際のフォント データを読み取るための操作は、ローカル ストレージ内のファイルを操作する場合とは異なります。 このような状況では、新しい下位レベルのインターフェイス IDWriteRemoteFontFileLoader がWindows 10 Creators Updateに追加されました。
リモート フォント ファイル ローダーを使用するには、最初にDirectWrite ファクトリに登録する必要があります。 ローダーは、アプリに関連付けられているフォントが使用されている限り、アプリによって保持される必要があります。 フォントが使用されなくなったら、ファクトリが破棄される前のある時点でローダーの登録を解除する必要があります。 これは、ローダー オブジェクトを所有する クラスのデストラクターで実行できます。 これらの手順を次に示します。
リモート フォントを使用してカスタム フォント セットを作成する方法は次のとおりです。これには、Windows 10 Creators Updateが必要です。
- 1. 上記のように IDWriteFactory5 インターフェイスを作成します。
2. 上記のように IDWriteFontSetBuilder インターフェイスを 作成します。
3. ファクトリを使用して IDWriteRemoteFontFileLoader を取得します。
- 上に示すように、フォント面のカスタム プロパティを定義します。
- 上に示すように、フォント の顔参照とカスタム プロパティをフォント セット ビルダーに追加します。
- すべてのフォントがフォント セット ビルダーに追加されたら、上記のようにフォント セットを作成します。
- リモート フォントが使用されなくなる時点で、リモート フォント ファイル ローダーの登録を解除します。
IDWriteRemoteFontFileLoader* pRemoteFontFileLoader;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateHttpFontFileLoader(
/* referrerURL */ nullptr,
/* extraHeaders */ nullptr,
&pRemoteFontFileLoader
);
}
これにより、アプリの代わりにフォント データをダウンロードするための HTTP 操作を処理できる、システム提供のリモート フォント ファイル ローダー インターフェイスの実装が返されます。 フォントのソースであるフォント サービスまたはサービスで必要な場合は、参照元 URL または追加ヘッダーを指定できます。
重要
セキュリティ上の注意: リモート フォントをフェッチしようとすると、攻撃者が呼び出される意図したサーバーをスプーフィングする可能性があります。 その場合、ターゲットと参照元の URL とヘッダーの詳細が攻撃者に開示されます。 アプリ開発者は、このリスクを軽減する責任があります。 HTTP ではなく HTTPS プロトコルを使用することをお勧めします。
1 つのリモート フォント ファイル ローダーを複数のフォントに使用できますが、参照元 URL または追加ヘッダーの要件が異なる複数のサービスからフォントを取得する場合は、異なるローダーを使用できます。
4. リモート フォント ファイル ローダーをファクトリに登録します。
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->RegisterFontFileLoader(pRemoteFontFileLoader);
}
この時点から、カスタム フォント セットを作成する手順は、既知のローカル フォント ファイルで説明されているものと似ていますが、2 つの重要な例外があります。 まず、 IDWriteFontFile オブジェクトは、ファクトリを使用するのではなく、リモート フォント ファイル ローダー インターフェイスを使用して作成されます。 次に、フォント データがローカルでないため、Analyze メソッドを使用できません。 代わりに、リモート フォント ファイルが OpenType Font Collection ファイルであるかどうかをアプリで認識する必要があります。その場合は、使用するコレクション内のどのフォントと、それぞれのインデックスを認識する必要があります。 そのため、残りの手順は次のとおりです。
5. リモート フォント ファイルごとに、リモート フォント ファイル ローダー インターフェイスを使用して IDWriteFontFile を作成し、フォント ファイルへのアクセスに必要な URL を指定します。
IDWriteFontFile* pFontFile;
hr = pRemoteFontFileLoader->CreateFontFileReferenceFromUrl(
pDWriteFactory,
/* baseUrl */ L"https://github.com/",
/* fontFileUrl */ L"winjs/winjs/blob/master/src/fonts/Symbols.ttf?raw=true",
&pFontFile
);
完全な URL は fontFileUrl パラメーターで指定することも、ベース部分と相対部分に分割することもできます。 ベース URL が指定されている場合、baseUrl と fontFileUrl の値を連結すると、完全な URL が提供される必要があります。DirectWriteは追加の区切り記号を指定しません。
重要
セキュリティ/パフォーマンスに関する注意: リモート フォントをフェッチしようとすると、Windows がサーバーから応答を受け取る保証はありません。 場合によっては、サーバーが無効な相対 URL のファイルが見つからないエラーで応答する場合がありますが、複数の無効な要求を受信した場合は応答を停止します。 サーバーが応答しない場合、Windows は最終的にタイムアウトしますが、複数のフェッチが開始された場合は数分かかる場合があります。 呼び出しが行われるときに URL が有効になるように、できることを行う必要があります。
また、URL は生の OpenType フォント ファイル (.ttf、.otf、.ttc、.otc) を指すことができますが、WOFF または WOFF2 コンテナー ファイル内のフォントを指すこともできます。 WOFF または WOFF2 ファイルが参照されている場合、リモート フォント ファイル ローダーのDirectWrite実装では、コンテナー ファイルからフォント データが自動的にアンパックされます。
6. 使用するリモート フォント ファイル内のフォント面インデックスごとに、 IDWriteFontFaceReference を作成します。
IDWriteFontFaceReference* pFontFaceReference;
hr = pDWriteFactory->CreateFontFaceReference(pFontFile, /* faceIndex */ 0, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
hr = pDWriteFactory->UnregisterFontFileLoader(pRemoteFontFileLoader);
カスタム リモート フォントを含むカスタム フォント セットが作成されると、フォント セットにはリモート フォントの参照と情報プロパティが含まれますが、実際のデータはまだリモートです。 リモート フォントのサポートDirectWrite、フォント セット内でフォントの面参照を維持し、レイアウトとレンダリングで使用するためにフォントを選択できますが、実際のデータは、テキスト レイアウトを実行する場合など、実際の使用が必要になるまでダウンロードされません。
アプリは、フォント データをダウンロードDirectWrite要求し、フォントでの処理が開始される前に正常なダウンロードの確認を待機することで、事前のアプローチを取ることができます。 ただし、ネットワークのダウンロードは予測不可能な期間の待機時間を意味し、成功も不確かです。 このため、通常は別の方法を使用することをお勧めします。レイアウトとレンダリングは、既にローカルの代替フォントまたはフォールバック フォントを使用して最初に実行できるようにし、目的のリモート フォントのダウンロードを並行して要求し、目的のフォントがダウンロードされたら結果を更新します。
フォント全体を使用する前にダウンロードするように要求するには、 IDWriteFontFaceReference::EnqueueFontDownloadRequest メソッドを使用できます。 フォントが非常に大きい場合は、特定の文字列を処理するためにデータの一部のみが必要になる場合があります。 DirectWriteには、特定のコンテンツに必要なフォント データの一部、EnqueueCharacterDownloadRequest、および EnqueueGlyphDownloadRequest を要求するために使用できる追加のメソッドが用意されています。
アプリで行うアプローチは、ローカル、代替、またはフォールバックフォントを使用して最初に処理を実行できるようにすることであるとします。 IDWriteFontFallback::MapCharacters メソッドを使用してローカル フォールバック フォントを識別できます。また、優先フォントをダウンロードする要求も自動的にエンキューされます。 また、IDWriteTextLayout が使用され、レイアウト内のテキストの一部またはすべてがリモート フォント参照を使用して書式設定されている場合、DirectWriteは自動的に MapCharacters メソッドを使用してローカル フォールバック フォントを取得し、リモート フォント データをダウンロードする要求をエンキューします。
DirectWriteでは、各ファクトリのフォント ダウンロード キューが保持され、上記のメソッドを使用して行われた要求がそのキューに追加されます。 フォント ダウンロード キューは、 IDWriteFactory3::GetFontDownloadQueue メソッドを使用して取得できます。
ダウンロード要求が行われたが、フォント データが既にローカルである場合は、no-op: 何もダウンロード キューに追加されません。 アプリは、IDWriteFontDownloadQueue::IsEmpty メソッドを呼び出すことによって、キューが空であるか、保留中のダウンロード要求があるかをチェックできます。
リモート フォント要求がキューに追加されたら、ダウンロード プロセスを開始する必要があります。 IDWriteTextLayout でリモート フォントが使用されている場合、GetLineMetrics メソッドや Draw メソッドなどのレイアウト操作またはレンダリング操作を強制する IDWriteTextLayout メソッドをアプリが呼び出すと、ダウンロードが自動的に開始されます。 他のシナリオでは、アプリは IDWriteFontDownloadQueue::BeginDownload を呼び出して直接ダウンロードを開始する必要があります。
ダウンロードが完了すると、アプリが適切なアクション (保留中の操作を続行するか、フォールバック フォントで最初に実行された繰り返し操作) を実行する必要があります。 (DirectWriteのテキスト レイアウトを使用している場合は、IDWriteTextLayout3::InvalidateLayout を使用して、フォールバック フォントを使用して計算された一時的な結果をクリアできます)。ダウンロード プロセスが完了したときにアプリに通知を受け取り、適切なアクションを実行するには、アプリで IDWriteFontDownloadListener インターフェイスの実装を提供し、これを BeginDownload 呼び出しに渡す必要があります。
重要
セキュリティ/パフォーマンスに関する注意: リモート フォントをフェッチしようとすると、Windows がサーバーから応答を受け取る保証はありません。 サーバーが応答しない場合、Windows は最終的にタイムアウトしますが、複数のリモート フォントがフェッチされているが失敗した場合は数分かかる場合があります。 BeginDownload 呼び出しはすぐに返されます。 IDWriteFontDownloadListener::D ownloadCompleted が呼び出されるのを待っている間、アプリは UI をブロックしないでください。
DirectWriteのフォント ダウンロード キューと IDWriteFontDownloadListener インターフェイスとの相互作用のサンプル実装は、DirectWrite カスタム フォント セットのサンプルと、DirectWriteダウンロード可能なフォントのサンプルでも確認できます。
メモリに読み込まれたフォント データを使用してカスタム フォント セットを作成する
フォント ファイルからデータを読み取るための低レベルの操作が、ローカル ディスク上のファイルと Web 上のリモート ファイルで異なるのと同様に、メモリ バッファーに読み込まれるフォント データについても同様です。 メモリ内フォント データを処理するための新しい低レベル インターフェイスが、Windows 10 Creators Update IDWriteInMemoryFontFileLoader に追加されました。
リモート フォント ファイル ローダーと同様に、メモリ内フォント ファイル ローダーを最初にDirectWrite ファクトリに登録する必要があります。 ローダーは、アプリに関連付けられているフォントが使用されている限り、アプリによって保持される必要があります。 フォントが使用されなくなったら、ファクトリが破棄される前のある時点で、ローダーの登録を解除する必要があります。 これは、ローダー オブジェクトを所有するクラスのデストラクターで実行できます。 これらの手順を次に示します。
アプリにデータによって表されるフォントの顔に関する個別の情報がある場合は、カスタム プロパティが指定されたフォント セット ビルダーに個々のフォント顔参照を追加できます。 ただし、フォント データはローカル メモリ内にあるため、これは必須ではありません。DirectWriteは、データを直接読み取ってプロパティ値を派生できます。
DirectWriteは、フォント データが OpenType ファイル (.ttf、.otf、.ttc、.otc) に相当する生の OpenType 形式であり、ディスクではなくメモリ内にあると想定しています。 データを WOFF または WOFF2 コンテナー形式にすることはできません。 データは OpenType Font Collection を表すことができます。 カスタム プロパティが使用されていない場合は、 IDWriteFontSetBuilder1::AddFontFile メソッドを使用して、データ内のすべてのフォントフェイスを 1 回の呼び出しで追加できます。
メモリ内シナリオの重要な考慮事項は、データの有効期間です。 バッファーへのポインターが、所有者があることを明確に示さずにDirectWriteに提供された場合、DirectWriteはデータのコピーを、所有する新しいメモリ バッファーに作成します。 データのコピーと追加のメモリ割り当てを回避するために、アプリは IUnknown を実装し、フォント データを含むメモリ バッファーを所有するデータ所有者オブジェクトを渡すことができます。 このインターフェイスを実装することで、DirectWriteオブジェクトの ref カウントに を追加できるため、所有データの有効期間を確保できます。
メモリ内フォント データを使用してカスタム フォント セットを作成する方法は次のとおりです。これには、Windows 10 Creators Updateが必要です。 これは、IUnknown を実装し、メモリ バッファーへのポインターとバッファーのサイズを返すメソッドを持つ、アプリで実装されたデータ所有者オブジェクトを想定します。
- 1. 上記のように IDWriteFactory5 インターフェイスを作成します。
2. 上記のように、[**IDWriteFontSetBuilder1**](/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontsetbuilder1) インターフェイスを作成します。
3. ファクトリを使用して IDWriteInMemoryFontFileLoader を取得します。
IDWriteInMemoryFontFileLoader* pInMemoryFontFileLoader;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateInMemoryFontFileLoader(&pInMemoryFontFileLoader);
}
これにより、メモリ内フォント ファイル ローダー インターフェイスのシステム提供の実装が返されます。
4. メモリ内フォント ファイル ローダーをファクトリに登録します。
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->RegisterFontFileLoader(pInMemoryFontFileLoader);
}
5. メモリ内フォント ファイルごとに、インメモリ フォント ファイル ローダーを使用して IDWriteFontFile を作成します。
IDWriteFontFile* pFontFile;
hr = pInMemoryFontFileLoader->CreateInMemoryFontFileReference(
pDWriteFactory,
pFontDataOwner->fontData /* returns void* */,
pFontDataOwner->fontDataSize /* returns UINT32 */,
pFontDataOwner /* ownerObject, owns the memory with font data and implements IUnknown */,
&pFontFile
);
6. 上に示すように、AddFontFile メソッドを使用して、IDWriteFontFile オブジェクトをフォント セット ビルダーに追加します。 必要に応じて、アプリは IDWriteFontFile に基づいて個別の IDWriteFontFaceReference オブジェクトを作成し、必要に応じて各フォントの顔参照のカスタム プロパティを定義し、次に、上に示すように AddFontFaceReference メソッドを使用して、カスタム プロパティを持つフォントの顔参照をフォント セットに追加できます。
7. すべてのフォントがフォント セット ビルダーに追加されたら、上記のようにカスタム フォント セットを作成します。
8. メモリ内フォントが使用されなくなる時点で、インメモリ フォント ファイル ローダーの登録を解除します。
hr = pDWriteFactory->UnregisterFontFileLoader(pInMemoryFontFileLoader);
高度なシナリオ
一部のアプリには、上記よりも高度な処理が必要な特別な要件がある場合があります。
フォント セットの組み合わせ
一部のアプリでは、他のフォント セットの項目の組み合わせで構成されるフォント セットを作成する必要がある場合があります。 たとえば、アプリでは、システムにインストールされているすべてのフォントをカスタム フォントの選択と組み合わせたフォント セットを作成したり、特定の条件に一致するインストール済みのフォントを他のフォントと組み合わせたりすることができます。 DirectWriteには、フォント セットの操作と組み合わせをサポートする API があります。
2 つ以上のフォント セットを結合するために、 IDWriteFontSetBuilder::AddFontSet メソッドは、指定されたフォント セット内のすべてのフォントを 1 回の呼び出しでフォント セット ビルダーに追加します。 既存のフォント セットの特定のフォントのみが新しいフォント セットで必要な場合は、 IDWriteFontSet::GetMatchingFonts メソッドを 使用して、指定したプロパティに一致するフォントのみを含むようにフィルター処理された新しいフォント セット オブジェクトを派生させることができます。 これらのメソッドを使用すると、2 つ以上の既存のフォント セットのフォントを組み合わせたカスタム フォント セットを簡単に作成できます
ローカル WOFF または WOFF2 フォント データの使用
アプリがローカル ファイル システムまたはメモリ バッファーにフォント ファイルを含み、WOFF または WOFF2 コンテナー形式を使用している場合、DirectWrite (Windows 10 Creator Update 以降) は、IDWriteFontFileStream を返すコンテナー形式 IDWriteFactory5::UnpackFontFile を開梱するためのメソッドを提供します。
ただし、アプリには、 IDWriteFontFileStream をフォント ファイル ローダー オブジェクトに取得する方法が必要です。 これを行う方法の 1 つは、ストリームをラップするカスタム IDWriteFontFileLoader 実装を作成することです。 他のフォント ファイル ローダーと同様に、これは使用前に登録し、ファクトリがスコープ外になる前に登録解除する必要があります。
カスタム ローダーが未加工の (パックされていない) フォント ファイルでも使用される場合、アプリはそれらのファイルを処理するために IDWriteFontFileStream インターフェイスのカスタム実装を提供する必要もあります。 ただし、生フォント ファイルを処理するために上記の API を使用する方が簡単な方法があります。 パックされたフォント ファイルと未加工のフォント ファイルに対して個別のコード パスを使用することで、カスタム ストリーム実装の必要性を回避できます。
カスタム フォント ファイル ローダー オブジェクトが作成されると、パックされたフォント ファイル データがアプリ固有の方法でローダーに追加されます。 ローダーは複数のフォント ファイルを処理できます。各フォント ファイルは、DirectWriteに不透明なアプリ定義キーを使用して識別されます。 パックされたフォント ファイルがローダーに追加されると、 IDWriteFactory::CreateCustomFontFileReference メソッドを使用して、特定のキーによって識別されるフォント データのそのローダーに基づいて IDWriteFontFile を取得します。
フォント データの実際のアンパックは、フォントがローダーに追加されるときに実行できますが、IDWriteFontFileLoader::CreateStreamFromKey メソッドでも処理できます。このメソッドは、最初にフォント データを読み取る必要があるときに呼び出DirectWrite。
IDWriteFontFile オブジェクトが作成された後、カスタム フォント セットにフォントを追加するための残りの手順は、前述のように行われます。
この方法を使用した実装は、カスタム フォント セットのDirectWriteサンプルに示されています。
カスタムの低レベルのネットワーク実装DirectWriteリモート フォント メカニズムを使用する
リモート フォントを処理するためのDirectWriteメカニズムは、リモート フォントのフォント顔参照を含むフォント セット、フォント データの局所性の確認、フォント ダウンロード要求のキューの管理など、上位レベルのメカニズムと、実際のダウンロードを処理する下位レベルのメカニズムに分けることができます。 一部のアプリでは、高レベルのリモート フォント メカニズムを利用する必要がある場合がありますが、HTTP 以外のプロトコルを使用してサーバーと通信するなど、カスタム ネットワーク操作も必要になります。
このような状況では、アプリは、必要な方法で他の下位レベルのインターフェイスと対話する IDWriteRemoteFontFileLoader インターフェイスのカスタム実装を作成する必要があります。 アプリでは、 IDWriteRemoteFontFileStream と IDWriteAsyncResult という下位レベルのインターフェイスのカスタム実装も提供 する必要があります。 これら 3 つのインターフェイスには、ダウンロード操作中に呼び出DirectWriteコールバック メソッドがあります。
IDWriteFontDownloadQueue::BeginDownload が呼び出されると、DirectWriteはデータの局所性に関するクエリをリモート フォント ファイル ローダーに対して行い、リモート ストリームを要求します。 データがローカルでない場合は、ストリームの BeginDownload メソッドを呼び出します。 ストリーム実装では、その呼び出しをブロックしないでくださいが、すぐに戻って、非同期ダウンロード操作の待機に使用DirectWrite待機ハンドルを提供する IDWriteAsyncResult オブジェクトを渡す必要があります。 カスタム ストリームの実装は、リモート通信の処理を担当します。 完了イベントが発生すると、DirectWriteは IDWriteAsyncResult::GetResult を呼び出して操作の結果を判断します。 結果が成功した場合は、ダウンロードした範囲のストリームに対する後続の ReadFragment 呼び出しが成功することが予想されます。
重要
セキュリティ/パフォーマンスに関する注意: リモート フォントをフェッチしようとすると、攻撃者が呼び出される目的のサーバーをスプーフィングしたり、サーバーが応答しなかったりする可能性があります。 カスタム ネットワーク操作を実装する場合は、サード パーティのサーバーを扱う場合よりも軽減策をより大きく制御できる可能性があります。 ただし、情報漏えいやサービス拒否を回避するための適切な軽減策を検討するのはユーザーの判断です。 HTTPS などのセキュリティで保護されたプロトコルをお勧めします。 また、DirectWriteに返されたイベント ハンドルが最終的に設定されるように、タイムアウトでビルドする必要があります。
以前のバージョンの Windows でのシナリオのサポート
既に説明したシナリオは、以前のバージョンの Windows では DirectWrite でサポートできますが、Windows 10より前に使用できる制限の多い API を使用して、アプリ側でさらに多くのカスタム実装が必要になります。 詳細については、「 カスタム フォント コレクション (Windows 7/8)」を参照してください。