2016-06-01 21 views
1

実行時にファイルからフォントをロードしてDirectWriteで表示しようとしています。次のコードは、そのフォントでIDWriteTextFormatオブジェクトを初期化する必要があります。それは、システムフォントで完璧に動作しますが、私はカスタムフォントファイルをロードする方法がわからないC++ - DirectWrite:実行時にファイルからフォントをロード

hr = pDWriteFactory->CreateTextFormat(
      L"Font Family", // Font family name 
      NULL,    // Font collection (NULL sets it to use the system font collection) 
           // Somehow, a custom font collection should be used here, but I don't know how to do that 
      DWRITE_FONT_WEIGHT_REGULAR, 
      DWRITE_FONT_STYLE_NORMAL, 
      DWRITE_FONT_STRETCH_NORMAL, 
      16.0f, 
      L"en-us", 
      &pTextFormat  // IDWriteTextFormat object 
     ); 

。私はどのようにそれを達成するための例を感謝します。
•私はthis articlethis question on Stackoverflowを読むが、1つのフォントファイルのファイルパスを渡す必要がどこに表示されていない(それゆえ、私は完全にそれらの上に提供されているコードのいずれかを実装するために失敗しました。私がこれまで試したどのような

2ページ)
•私はまたthis articleを読むが、私が正しいならば、それは(DirectWriteのとは何の関係もない?)(私はAddFontResourceEx-メソッドを実装しようとしたが、無駄に)
•最後に、答えをthis question ResourceFontContext :: CreateFontCollectionを使用して問題を解決できますが、this page(ドイツ語ですが、scre私はそれがリソースとして埋め込まれたフォント(私の場合はオプションではない)でしか使用できないと信じています。

答えて

3

確かにそれは可能です。

  • IDWriteFontCollectionLoaderインターフェイスをコードに実装する必要があります。

    明らかにIDWriteFontFileEnumeratorを実装する必要がありますが、これは簡単なことです。 CreateCustomFontCollectionを使用して収集し、同工場を作成RegisterFontCollectionLoader

  • を使用して、工場で

  • レジスタローダー;

  • 同じ工場で呼び出されたCreateTextFormatに渡してください。

CreateCustomFontCollectionに電話すると、コレクションキーとそのサイズを指定する必要があります。これは、あなたにとって意味のあるBLOBです。何でもかまいません。後でこのキーでローダーが呼び出されるので、それを識別することができます。たとえば、文字列「myspecialkey」をキーとして使用できます。CreateEnumeratorFromKeyは、そのキーで呼び出されているかどうかをチェックし、他のキーは拒否します。

ファイルへのパスからフォントフェースオブジェクトを作成する場合は、上記のいずれも必要ありません。CreateFontFileReferenceとそれに続くCreateFontFaceを使用してください。

+0

'IDWriteFontFace'は問題を解決していないようです([この質問](http://stackoverflow.com/questions/11921592/how-to-create-idwritetextformat-from-idwritefontfaceを参照))。カスタムフォントを作成してコンパイルするコードを作成することはできますが、カスタムフォントを追加する場所はわかりません。 –

+0

あなたは物理的なフォントファイルをどこに追加するのですか?それは、あなたが提供するカスタムコレクションコードが直接的なシステムにアクセスできるようにする限り、別個のファイル、実行可能ファイル内の組み込みリソース、まったく何かである可能性があります。 – bunglehead

+0

私は完全に間違ったところにいると信じています。私は現在[このページ](https://msdn.microsoft.com/de-de/library/windows/desktop/dd941728(v = vs.85).aspx)を見ていて、自分のコードに適応しようとしています。私が数分で成功すれば教えてくれます。 –

2

誰が最終的に働いていたコードに興味がある場合:
は、アプリケーションに次の行をプロジェクトにCommon.hFontLoader.hFontLoader.cppを追加します(コードは以下のとおりである)とを追加:

#include "FontLoader.h" 
// ... 
IDWriteFactory* pDWriteFactory; 
IDWriteFontCollection *fCollection; 
IDWriteTextFormat* pTextFormat; 
// ... 
MFFontContext fContext(pDWriteFactory); 
std::vector<std::wstring> filePaths; // vector containing ABSOLUTE file paths of the font files which are to be added to the collection 
std::wstring fontFileFilePath = L"C:\\xyz\\abc.ttf"; 
filePaths.push_back(fontFileFilePath); 
HRESULT hr = fContext.CreateFontCollection(filePaths, &fCollection); // create custom font collection 
hr = pDWriteFactory->CreateTextFormat(
      L"Font Family", // Font family name 
      fCollection, 
      DWRITE_FONT_WEIGHT_REGULAR, 
      DWRITE_FONT_STYLE_NORMAL, 
      DWRITE_FONT_STRETCH_NORMAL, 
      16.0f, 
      L"en-us", 
      &pTextFormat  // IDWriteTextFormat object 
     ); 

FontLoader。 H

#pragma once 
#include <string> 
#include "Common.h" 

typedef std::vector<std::wstring> MFCollection; 

class MFFontCollectionLoader : public IDWriteFontCollectionLoader 
{ 
public: 
    MFFontCollectionLoader() : refCount_(0) 
    { 
    } 

    // IUnknown methods 
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); 
    virtual ULONG STDMETHODCALLTYPE AddRef(); 
    virtual ULONG STDMETHODCALLTYPE Release(); 

    // IDWriteFontCollectionLoader methods 
    virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
     IDWriteFactory* factory, 
     void const* collectionKey,      // [collectionKeySize] in bytes 
     UINT32 collectionKeySize, 
     OUT IDWriteFontFileEnumerator** fontFileEnumerator 
    ); 

    // Gets the singleton loader instance. 
    static IDWriteFontCollectionLoader* GetLoader() 
    { 
     return instance_; 
    } 

    static bool IsLoaderInitialized() 
    { 
     return instance_ != NULL; 
    } 

private: 
    ULONG refCount_; 

    static IDWriteFontCollectionLoader* instance_; 
}; 

class MFFontFileEnumerator : public IDWriteFontFileEnumerator 
{ 
public: 
    MFFontFileEnumerator(
     IDWriteFactory* factory 
    ); 

    HRESULT Initialize(
     UINT const* collectionKey, // [resourceCount] 
     UINT32 keySize 
    ); 

    ~MFFontFileEnumerator() 
    { 
     SafeRelease(&currentFile_); 
     SafeRelease(&factory_); 
    } 

    // IUnknown methods 
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); 
    virtual ULONG STDMETHODCALLTYPE AddRef(); 
    virtual ULONG STDMETHODCALLTYPE Release(); 

    // IDWriteFontFileEnumerator methods 
    virtual HRESULT STDMETHODCALLTYPE MoveNext(OUT BOOL* hasCurrentFile); 
    virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(OUT IDWriteFontFile** fontFile); 

private: 
    ULONG refCount_; 

    IDWriteFactory* factory_; 
    IDWriteFontFile* currentFile_; 
    std::vector<std::wstring> filePaths_; 
    size_t nextIndex_; 
}; 

class MFFontContext 
{ 
public: 
    MFFontContext(IDWriteFactory *pFactory); 
    ~MFFontContext(); 

    HRESULT Initialize(); 

    HRESULT CreateFontCollection(
     MFCollection &newCollection, 
     OUT IDWriteFontCollection** result 
    ); 

private: 
    // Not copyable or assignable. 
    MFFontContext(MFFontContext const&); 
    void operator=(MFFontContext const&); 

    HRESULT InitializeInternal(); 
    IDWriteFactory *g_dwriteFactory; 
    static std::vector<unsigned int> cKeys; 

    // Error code from Initialize(). 
    HRESULT hr_; 
}; 

class MFFontGlobals 
{ 
public: 
    MFFontGlobals() {} 
    static unsigned int push(MFCollection &addCollection) 
    { 
     unsigned int ret = fontCollections.size(); 
     fontCollections.push_back(addCollection); 
     return ret; 
    } 
    static std::vector<MFCollection>& collections() 
    { 
     return fontCollections; 
    } 
private: 
    static std::vector<MFCollection> fontCollections; 
}; 

FontLoader.cpp

#include "FontLoader.h" 

IDWriteFontCollectionLoader* MFFontCollectionLoader::instance_(
    new(std::nothrow) MFFontCollectionLoader() 
); 

HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) 
{ 
    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) 
    { 
     *ppvObject = this; 
     AddRef(); 
     return S_OK; 
    } 
    else 
    { 
     *ppvObject = NULL; 
     return E_NOINTERFACE; 
    } 
} 

ULONG STDMETHODCALLTYPE MFFontCollectionLoader::AddRef() 
{ 
    return InterlockedIncrement(&refCount_); 
} 

ULONG STDMETHODCALLTYPE MFFontCollectionLoader::Release() 
{ 
    ULONG newCount = InterlockedDecrement(&refCount_); 
    if (newCount == 0) 
     delete this; 

    return newCount; 
} 

HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::CreateEnumeratorFromKey(
    IDWriteFactory* factory, 
    void const* collectionKey,      // [collectionKeySize] in bytes 
    UINT32 collectionKeySize, 
    OUT IDWriteFontFileEnumerator** fontFileEnumerator 
) 
{ 
    *fontFileEnumerator = NULL; 

    HRESULT hr = S_OK; 

    if (collectionKeySize % sizeof(UINT) != 0) 
     return E_INVALIDARG; 

    MFFontFileEnumerator* enumerator = new(std::nothrow) MFFontFileEnumerator(
     factory 
    ); 
    if (enumerator == NULL) 
     return E_OUTOFMEMORY; 

    UINT const* mfCollectionKey = static_cast<UINT const*>(collectionKey); 
    UINT32 const mfKeySize = collectionKeySize; 

    hr = enumerator->Initialize(
     mfCollectionKey, 
     mfKeySize 
    ); 

    if (FAILED(hr)) 
    { 
     delete enumerator; 
     return hr; 
    } 

    *fontFileEnumerator = SafeAcquire(enumerator); 

    return hr; 
} 

// ------------------------------ MFFontFileEnumerator ---------------------------------------------------------- 

MFFontFileEnumerator::MFFontFileEnumerator(
    IDWriteFactory* factory 
) : 
    refCount_(0), 
    factory_(SafeAcquire(factory)), 
    currentFile_(), 
    nextIndex_(0) 
{ 
} 

HRESULT MFFontFileEnumerator::Initialize(
    UINT const* collectionKey, // [resourceCount] 
    UINT32 keySize 
) 
{ 
    try 
    { 
     // dereference collectionKey in order to get index of collection in MFFontGlobals::fontCollections vector 
     UINT cPos = *collectionKey; 
     for (MFCollection::iterator it = MFFontGlobals::collections()[cPos].begin(); it != MFFontGlobals::collections()[cPos].end(); ++it) 
     { 
      filePaths_.push_back(it->c_str()); 
     } 
    } 
    catch (...) 
    { 
     return ExceptionToHResult(); 
    } 
    return S_OK; 
} 

HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) 
{ 
    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) 
    { 
     *ppvObject = this; 
     AddRef(); 
     return S_OK; 
    } 
    else 
    { 
     *ppvObject = NULL; 
     return E_NOINTERFACE; 
    } 
} 

ULONG STDMETHODCALLTYPE MFFontFileEnumerator::AddRef() 
{ 
    return InterlockedIncrement(&refCount_); 
} 

ULONG STDMETHODCALLTYPE MFFontFileEnumerator::Release() 
{ 
    ULONG newCount = InterlockedDecrement(&refCount_); 
    if (newCount == 0) 
     delete this; 

    return newCount; 
} 

HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::MoveNext(OUT BOOL* hasCurrentFile) 
{ 
    HRESULT hr = S_OK; 

    *hasCurrentFile = FALSE; 
    SafeRelease(&currentFile_); 

    if (nextIndex_ < filePaths_.size()) 
    { 
     hr = factory_->CreateFontFileReference(
      filePaths_[nextIndex_].c_str(), 
      NULL, 
      &currentFile_ 
     ); 

     if (SUCCEEDED(hr)) 
     { 
      *hasCurrentFile = TRUE; 

      ++nextIndex_; 
     } 
    } 

    return hr; 
} 

HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::GetCurrentFontFile(OUT IDWriteFontFile** fontFile) 
{ 
    *fontFile = SafeAcquire(currentFile_); 

    return (currentFile_ != NULL) ? S_OK : E_FAIL; 
} 

// ---------------------------------------- MFFontContext --------------------------------------------------------- 

MFFontContext::MFFontContext(IDWriteFactory *pFactory) : hr_(S_FALSE), g_dwriteFactory(pFactory) 
{ 
} 

MFFontContext::~MFFontContext() 
{ 
    g_dwriteFactory->UnregisterFontCollectionLoader(MFFontCollectionLoader::GetLoader()); 
} 

HRESULT MFFontContext::Initialize() 
{ 
    if (hr_ == S_FALSE) 
    { 
     hr_ = InitializeInternal(); 
    } 
    return hr_; 
} 

HRESULT MFFontContext::InitializeInternal() 
{ 
    HRESULT hr = S_OK; 

    if (!MFFontCollectionLoader::IsLoaderInitialized()) 
    { 
     return E_FAIL; 
    } 

    // Register our custom loader with the factory object. 
    hr = g_dwriteFactory->RegisterFontCollectionLoader(MFFontCollectionLoader::GetLoader()); 

    return hr; 
} 

HRESULT MFFontContext::CreateFontCollection(
    MFCollection &newCollection, 
    OUT IDWriteFontCollection** result 
) 
{ 
    *result = NULL; 

    HRESULT hr = S_OK; 

    // save new collection in MFFontGlobals::fontCollections vector 
    UINT collectionKey = MFFontGlobals::push(newCollection); 
    cKeys.push_back(collectionKey); 
    const void *fontCollectionKey = &cKeys.back(); 
    UINT32 keySize = sizeof(collectionKey); 

    hr = Initialize(); 
    if (FAILED(hr)) 
     return hr; 

    hr = g_dwriteFactory->CreateCustomFontCollection(
     MFFontCollectionLoader::GetLoader(), 
     fontCollectionKey, 
     keySize, 
     result 
    ); 

    return hr; 
} 

std::vector<unsigned int> MFFontContext::cKeys = std::vector<unsigned int>(0); 

// ----------------------------------- MFFontGlobals --------------------------------------------------------- 

std::vector<MFCollection> MFFontGlobals::fontCollections = std::vector<MFCollection>(0); 

コモン。時間

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE. 
// 
// Copyright (c) Microsoft Corporation. All rights reserved 
// 
//---------------------------------------------------------------------------- 

#pragma once 

// The following macros define the minimum required platform. The minimum required platform 
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 
// your application. The macros work by enabling all features available on platform versions up to and 
// including the version specified. 

// Modify the following defines if you have to target a platform prior to the ones specified below. 
// Refer to MSDN for the latest info on corresponding values for different platforms. 

#ifndef WINVER     // Minimum platform is Windows 7 
#define WINVER 0x0601 
#endif 

#ifndef _WIN32_WINNT   // Minimum platform is Windows 7 
#define _WIN32_WINNT 0x0601 
#endif 

#ifndef _WIN32_WINDOWS   // Minimum platform is Windows 7 
#define _WIN32_WINDOWS 0x0601 
#endif 

#define WIN32_LEAN_AND_MEAN 
#define NOMINMAX 

#ifndef UNICODE 
#define UNICODE 
#endif 

// Windows header files 
#include <windows.h> 
#include <dwrite.h> 
#include <d2d1.h> 

// C RunTime Header Files 
#include <stdlib.h> 
#include <malloc.h> 
#include <memory.h> 
#include <memory> 
#include <vector> 

// Ignore unreferenced parameters, since they are very common 
// when implementing callbacks. 
#pragma warning(disable : 4100) 


//////////////////////////////////////// 
// COM inheritance helpers. 

// Releases a COM object and nullifies pointer. 
template <typename InterfaceType> 
inline void SafeRelease(InterfaceType** currentObject) 
{ 
    if (*currentObject != NULL) 
    { 
     (*currentObject)->Release(); 
     *currentObject = NULL; 
    } 
} 


// Acquires an additional reference, if non-null. 
template <typename InterfaceType> 
inline InterfaceType* SafeAcquire(InterfaceType* newObject) 
{ 
    if (newObject != NULL) 
     newObject->AddRef(); 

    return newObject; 
} 


// Sets a new COM object, releasing the old one. 
template <typename InterfaceType> 
inline void SafeSet(InterfaceType** currentObject, InterfaceType* newObject) 
{ 
    SafeAcquire(newObject); 
    SafeRelease(&currentObject); 
    currentObject = newObject; 
} 


// Maps exceptions to equivalent HRESULTs, 
inline HRESULT ExceptionToHResult() throw() 
{ 
    try 
    { 
     throw; // Rethrow previous exception. 
    } 
    catch (std::bad_alloc&) 
    { 
     return E_OUTOFMEMORY; 
    } 
    catch (...) 
    { 
     return E_FAIL; 
    } 
} 

コードは確かに完璧ではないですが、それは私のために働きました。
このコードに関するご質問はコメントをお寄せください。

+0

Windows 10 Fall SDK 16232で少し楽になりました。 dwriteFactory-> CreateFontSetBuilder(OUT&fontSetBuilder2); fontSetBuilder2-> AddFontFile(fullFontFilePath.c_str()); fontSetBuilder2-> CreateFontSet(OUT&fontSet); dwriteFactory3-> CreateFontCollectionFromFontSet(fontSet、OUT&fontCollection); –

関連する問題