2011-04-22 130 views
2

使用CreateFont可以指定字體名稱和一堆其他屬性。但是,如果我有一個font.ttf文件,並且我想讓該特定字體由Windows加載?我如何指定要使用的特定文件?使用Windows API加載ttf字體

+0

不會CreateFontIndirectEx是一個選項呢?在那裏你可以挑選。 – 0xC0000022L 2011-04-22 16:00:45

+0

@STATUS_ACCESS_DENIED:我沒有看到任何地方指定一個文件名,只是一個'臉名',我懷疑是在系統字體表中查找某處。也許我可以'AddFontResourceEx',然後使用它,然後'RemoveFontResourceEx',但那麼我怎麼弄出什麼名稱窗口放它,所以我可以加載它'CreateFont'? – Claudiu 2011-04-22 16:04:50

+0

替代; GDI + PrivateFontCollection然後你可以枚舉集合並獲取姓氏 – 2011-04-22 16:15:46

回答

3

我敢肯定你不能。所有對字體的請求都會通過字體映射器,然後它會挑選最接近符合您所提供規格的字體文件。雖然我不確定它是否在現實中,但它至少理論上可以使用(例如)來自兩個完全獨立的字體文件的數據來創建一個邏輯字體。

+0

會有一種方法可以解析'ttf'文件來獲取它的所有屬性,以便我可以安裝它,然後將這些屬性傳遞給窗口以獲取該特定字體? – Claudiu 2011-04-22 16:32:54

+0

@Claudiu:是的,但這絕對不是你自己做的。我可能會使用類似Freetype(Freetype 2,真的)來訪問字體文件中的數據。 – 2011-04-22 17:01:02

+0

是的,我只是列舉了現有的Windows字體來解決我的問題。 – Claudiu 2011-08-25 14:36:01

1

如果你不關心你安裝可以用AddFontResource這樣做的字體,那麼你可以通過在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts看映射獲取物理.TTF和它的邏輯/姓氏之間的關係。

我在評論中提到PrivateFontCollection因爲我以爲你想暫時做到這一點;你可以加載一個TTF爲PFC與PrivateFontCollection::AddFontFile,從收集& examime GetFamilyName接回新FontFamily對象。 (我已經做了與.NET實現這一點,但不是原始API類似)

+0

AddFontResource實際上並沒有持續添加到註冊表以重新啓動,只是臨時到GDI的系統表。當您通過shell安裝字體(通過右鍵單擊該文件)時,它會調用AddFontResource,更新註冊表項並廣播WM_FONTCHANGE。 http://msdn.microsoft.com/en-us/library/windows/desktop/dd144833(v=vs.85).aspx – 2014-08-28 21:06:12

+0

這就是爲什麼沒有標記爲FR_PRIVATE的ttf文件被PID 4採用:P – 2014-10-10 09:26:29

2

一種可能性是EnumFonts(),保存結果。然後再次添加您的私人字體AddFontResourceEx()EnumFonts(),不同之處在於您添加的內容。請注意,TTF和位圖字體枚舉方式不同,但對於此測試,這應該不重要。

如果您正在使用位圖字體,他們可以很容易地解析(.FNT和.FON)。您可能必須構建TTF(或借用其他評論者建議的FreeType)解析器,以將「名稱」表從TTF文件中提取出來。

對於您正在控制或提供給您的應用的字體而言,這看起來像是很多工作。

我們使用AddFontResourceEx()添加一個私人字體,但由於我們控制了我們添加的字體,我們只是硬編碼傳遞到CreateFontIndirect()的字體名稱以匹配。

+0

這樣做的麻煩是如果你添加一個已經安裝的字體,那麼差異將是空的。 – 2012-02-07 14:46:20

+0

如果您將字體標記爲FR_PRIVATE,然後使用其名稱命名CreateFontIndirect,則您的應用將使用該字體,並覆蓋具有相同名稱的系統字體。 – 2014-10-10 09:25:04

3

這是無可否認的,而間接的,但在Windows 7+運行時,你可以利用GDI互操作與DWRITE。

#include <Windows.h> 
#include <WindowsX.h> 
#include <DWrite.h> 

... 

// Make the font file visible to GDI. 
AddFontResourceEx(fontFileName, FR_PRIVATE, 0); 
if (SUCCEEDED(GetLogFontFromFileName(fontFileName, &logFont))) 
{ 
    logFont.lfHeight = -long(desiredPpem); 
    HFONT hf = CreateFontIndirect(&logFont); 
    HFONT oldFont = SelectFont(hdc, hf); 
    ... 
    // Do stuff... 
    ... 
    SelectFont(hdc, oldFont); 
} 
RemoveFontResource(fontFileName); 

.... 

HRESULT GetLogFontFromFileName(_In_z_ wchar const* fontFileName, _Out_ LOGFONT* logFont) 
{ 
    // DWrite objects 
    ComPtr<IDWriteFactory> dwriteFactory; 
    ComPtr<IDWriteFontFace> fontFace; 
    ComPtr<IDWriteFontFile> fontFile; 
    ComPtr<IDWriteGdiInterop> gdiInterop; 

    // Set up our DWrite factory and interop interface. 
    IFR(DWriteCreateFactory(
     DWRITE_FACTORY_TYPE_SHARED, 
     __uuidof(IDWriteFactory), 
     reinterpret_cast<IUnknown**>(&dwriteFactory) 
     ); 
    IFR(g_dwriteFactory->GetGdiInterop(&gdiInterop)); 

    // Open the file and determine the font type. 
    IFR(g_dwriteFactory->CreateFontFileReference(fontFileName, nullptr, &fontFile)); 
    BOOL isSupportedFontType = false; 
    DWRITE_FONT_FILE_TYPE fontFileType; 
    DWRITE_FONT_FACE_TYPE fontFaceType; 
    UINT32 numberOfFaces = 0; 
    IFR(fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces)); 

    if (!isSupportedFontType) 
     return DWRITE_E_FILEFORMAT; 

    // Set up a font face from the array of font files (just one) 
    ComPtr<IDWriteFontFile> fontFileArray[] = {fontFile}; 
    IFR(g_dwriteFactory->CreateFontFace(
     fontFaceType, 
     ARRAYSIZE(fontFileArray), // file count 
     &fontFileArray[0], // or GetAddressOf if WRL ComPtr 
     0, // faceIndex 
     DWRITE_FONT_SIMULATIONS_NONE, 
     &fontFace 
     ); 

    // Get the necessary logical font information. 
    IFR(gdiInterop->ConvertFontFaceToLOGFONT(fontFace, OUT logFont)); 

    return S_OK; 
} 

哪裏IFR就是這樣一個失敗的HRESULT返回失敗宏,ComPtr是一個輔助智能指針類(代替你自己的,或ATL但是CComPtr,WinRT的ComPtr,VS2013 _com_ptr_t ...)。