如何优先选择AddFontMemResourceEx加载的字体而非系统字体?

4

我正在使用C++在Windows上开发游戏应用程序,并使用资源中包含的字体。

我可以通过AddFontMemResourceExCreateFont加载字体。
并且,在没有安装任何特殊字体的环境下,我可以正确地使用加载的字体呈现文字。

但是,世界上存在着不同版本的字体。
如果系统中已经安装了其他版本的字体,CreateFont将通过字体名称(pszFaceName)查找字体,并不方便地优先选择系统字体。
有没有什么办法可以优先选择由AddFontMemResourceEx加载的专用字体呢?

值得一提的是AddFontMemResourceEx的返回值是HANDLE,但我无法找到任何使用它来进行CreateFont的代码。
可能通过编辑专用字体的字体系列可以避免冲突。 但是,如果可以的话,我想通过编程来解决。

HANDLE handle = AddFontMemResourceEx(data, readBytes, NULL, &fontNum);

hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS,
                   CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UmePlus CL Gothic");

AddFontMemResourceEx() 返回的 HANDLE 只能用于 RemoveFontMemResourceEx()。我不知道有什么方法可以优先使用内存字体而不是其他已安装的字体。系统中只有一个字体表,CreateFont(Indirect)() 会加载最适合您指定特征的字体。如果另一个字体比您的内存字体更匹配,那么就使用它吧。 - Remy Lebeau
2
在调用AddFontMemResourceEx之前,您可以在内存中动态更改字体的面名。您需要复制资源数据才能进行写入。OpenType规范 - zett42
1个回答

2
感谢您的评论!
根据评论,我已经在内存中替换了字体名称。
但是,由于大小端差异,此代码有一定的复杂性。
注意:newFontName必须比oldFontName短。
#pragma pack(1)
typedef struct {
    short version;
    long numTables;
    short searchRange;
    short entrySelector;
    short rangeShift;
} TTF_HEADER;

typedef struct {
    char name[4];
    long checksum;
    long offset;
    long length;
} TTF_OFFSET_TABLE;

typedef struct {
    short format;
    short count;
    short stringOffset;
} TTF_NAME_TABLE_HEADER;

typedef struct {
    short platformId;
    short specificId;
    short languageId;
    short nameId;
    short length;
    short offset;
} TTF_NAME_TABLE_ENTRY;
#pragma pack()

void copySwappedWchar(const wchar_t* src, wchar_t* dest, int length) {
    for (int i = 0; i < length; i++) {
        dest[i] = _byteswap_ushort(src[i]);
    }
}

void renameLocalFont(unsigned char* data, const wchar_t* oldFontName, const wchar_t* newFontName) {
    TTF_HEADER* header = (TTF_HEADER*)data;
    unsigned char* offsetTableBase = data + sizeof(TTF_HEADER);
    for (int i = 0; i < _byteswap_ulong(header->numTables); i++) {
        TTF_OFFSET_TABLE* table = (TTF_OFFSET_TABLE*)(offsetTableBase + sizeof(TTF_OFFSET_TABLE) * i);
        if (memcmp(table->name, "name", 4) != 0) continue;

        TTF_NAME_TABLE_HEADER* nameTable = (TTF_NAME_TABLE_HEADER*)(data + _byteswap_ulong(table->offset));
        unsigned char* entryBase = data + _byteswap_ulong(table->offset) + sizeof(TTF_NAME_TABLE_HEADER);
        for (int j = 0; j < _byteswap_ushort(nameTable->count); j++) {
            TTF_NAME_TABLE_ENTRY* entry = (TTF_NAME_TABLE_ENTRY*)(entryBase + sizeof(TTF_NAME_TABLE_ENTRY) * j);
            wchar_t* dest = new wchar_t[_byteswap_ushort(entry->length) + 1];
            wchar_t* src = (wchar_t*)(data + _byteswap_ulong(table->offset) + _byteswap_ushort(nameTable->stringOffset) + _byteswap_ushort(entry->offset));
            copySwappedWchar((const wchar_t*)src, dest, _byteswap_ushort(entry->length) + 1);
            if (wcscmp(dest, oldFontName) == 0) {
                copySwappedWchar(newFontName, src, wcslen(newFontName) + 1);
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接