gpt4 book ai didi

c++ - 根据字体句柄获取字体文件名 (HFONT)

转载 作者:可可西里 更新时间:2023-11-01 13:06:17 26 4
gpt4 key购买 nike

我遇到过这样一种情况,我们需要知道 QFont 当前使用的字体的文件名。 .知道一个QFont可以给我们字体系列和 Windows HFONT处理。

字体系列是不够的,因为像Bold这样的操作样式或 Italic会导致 Windows 选择不同的字体文件。 (例如 arial.ttf、arialbd.ttf、arialbi.ttf、ariali.ttf)。

这段代码示例应该给我们 <path>\arial.ttf :

QFont font("Arial", 12);
FindFontFileName(font.handle());

虽然这段代码示例应该给我们 <path>\arialbi.ttf

QFont font("Arial", 12);
font.setStyle(QFont::StyleItalic);
font.setWeight(QFont::Bold);
FindFontFileName(font.handle());

最佳答案

Windows API Font and Text Functions不包含返回字体文件名的函数。因此,必须制定出更具创造性的解决方案。

解决方案是使用 GetFontData函数,它将为我们提供原始字体文件的精确拷贝。唯一剩下的就是将此数据与所有已安装/已知字体的内容进行比较。

查找表

我们将首先创建一个包含所有已安装/已知字体的查找表 (FontList):

#define FONT_FINGERPRINT_SIZE    256
struct FontListItem
{
std::string FileName;
int FingerPrintOffset;
char FingerPrint[FONT_FINGERPRINT_SIZE];
};

std::multimap< size_t, std::shared_ptr<FontListItem> > FontList;

FingerPrint 是从字体文件中读取的随机部分,用于区分相同文件大小的字体。您还可以使用完整文件的哈希值(例如 SHA1)来确定这一点。

添加字体

将单个字体添加到此列表的方法非常简单:

void AddFontToList(const std::string& fontFileName)
{
std::ifstream file(fontFileName, std::ios::binary | std::ios::ate);
if (!file.is_open())
return;

size_t fileSize = file.tellg();
if (fileSize < FONT_FINGERPRINT_SIZE)
return;

std::shared_ptr<FontListItem> fontListItem(new FontListItem());
fontListItem->FileName = fontFileName;
fontListItem->FingerPrintOffset = rand() % (fileSize - FONT_FINGERPRINT_SIZE);
file.seekg(fontListItem->FingerPrintOffset);
file.read(fontListItem->FingerPrint, FONT_FINGERPRINT_SIZE);
FontList.insert(std::pair<size_t, std::shared_ptr<FontListItem> >(fileSize, fontListItem));
}

将所有 Windows 字体添加到查找表的 Qt 方法如下:

const QDir dir(QString(getenv("WINDIR")) + "\\fonts");
dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
foreach (const QFileInfo fileInfo, dir.entryInfoList())
AddFontToList(fileInfo.absoluteFilePath().toUtf8().constData());

文件枚举也可以使用 FindFirstFile 完成/FindNextFile Windows API 函数,但就此答案而言可读性较差。

GetFontData 帮助程序

然后我们为 GetFontData 函数创建一个包装函数,它创建一个 DC,通过 HFONT 句柄选择字体并返回字体数据:

bool GetFontData(const HFONT fontHandle, std::vector<char>& data)
{
bool result = false;
HDC hdc = ::CreateCompatibleDC(NULL);
if (hdc != NULL)
{
::SelectObject(hdc, fontHandle);
const size_t size = ::GetFontData(hdc, 0, 0, NULL, 0);
if (size > 0)
{
char* buffer = new char[size];
if (::GetFontData(hdc, 0, 0, buffer, size) == size)
{
data.resize(size);
memcpy(&data[0], buffer, size);
result = true;
}
delete[] buffer;
}
::DeleteDC(hdc);
}
return result;
}

字体文件名查找

现在我们已经准备好通过只知道HFONT 句柄来查找字体的确切文件名:

std::string FindFontFileName(const HFONT fontHandle)
{
std::vector<char> data;
if (GetFontData(fontHandle, data))
{
for (auto i = FontList.lower_bound(data.size()); i != FontList.upper_bound(data.size()); ++i)
{
if (memcmp(&data[i->second->FingerPrintOffset], i->second->FingerPrint, FONT_FINGERPRINT_SIZE) == 0)
return i->second->FileName;
}
}
return std::string();
}

关于c++ - 根据字体句柄获取字体文件名 (HFONT),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16769758/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com