winapi - Indlæs en ttf-skrifttype med Windows API

Indlæg af Hanne Mølgaard Plasc

Problem



Med CreateFont kan man angive skrifttypenavn og en flok andre egenskaber. Men hvad hvis jeg har en font.ttf fil, og jeg vil have, at den pågældende skrifttype skal læses af Windows? Hvordan specificerer jeg den specifikke fil, der skal bruges?

Bedste reference


Jeg er temmelig sikker på, at du kan. T. Alle anmodninger om skrifttyper går gennem fontmappen, og det henter den skrifttypefil, der kommer tættest på at opfylde de specifikationer, du har givet. Selvom jeg ikke er sikker på, at det endda gør det i virkeligheden, kunne den i det mindste teoretisk bruge eksempel) data fra to helt separate skrifttypefiler for at oprette en logisk skrifttype.

Andre referencer 1


Det er ganske vist ret indirekte, men du kan bruge GDI interop med DWrite, når du kører på Windows 7+.


#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;
}


Hvor IFR er en fejlmakro, der returnerer på et FAILED HRESULT, og ComPtr er en hjælper smart pointer klasse (erstatning med din egen eller ATL CComPtr, WinRT ComPtr, VS2013 \_com\_ptr\_t ...).

Andre referencer 2


En mulighed er at EnumFonts(), gem resultaterne. Tilføj derefter din private skrifttype med AddFontResourceEx() og EnumFonts() igen, forskellen er, hvad du tilføjede. Bemærk, at TTF og bitmap skrifttyper opregner forskelligt, men for denne test, bør det ikke være noget.


Hvis du bruger bitmap skrifttyper, kunne de let analyseres (.FNT og .FON). TTF du 'sandsynligvis skal bygge (eller låne som en anden kommenteret foreslået FreeType) en parser til at trække' navn 'tabellen ud af TTF filen.


Det virker som en masse arbejde for en skrifttype, du kontrollerer eller leverer med din app.


Vi bruger AddFontResourceEx () for at tilføje en privat skrifttype, men da vi kontrollerer skrifttypen, tilføjer vi, vi bare hardcode fontname overført til CreateFontIndirect() for at matche.

Andre referencer 3


Hvis du ikke bryr dig om at installere skrifttypen, kan du gøre det med AddFontResource, så kan du hente forholdet mellem det fysiske .TTF og det logiske/familienavn ved at se på mappings i HKEY\_LOCAL\_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionFonts.


Jeg nævnte PrivateFontCollection i min kommentar, fordi jeg troede, at du ønskede at gøre dette midlertidigt; du kan indlæse en TTF til en PFC med PrivateFontCollection::AddFontFile, hent det nye FontFamily objekt fra samlingen & eksamen GetFamilyName. (Jeg har gjort det samme med .net implementeringen af ​​dette, men ikke det rå API) [13]