cpp
复制代码
#include "FontInfo.h"
#include <iostream>
FontInfo::FontInfo()
: ascent(0), descent(0), lineGap(0), capHeight(0), xHeight(0),
underlinePosition(0), underlineThickness(0),
strikethroughPosition(0), strikethroughThickness(0),
weight(DWRITE_FONT_WEIGHT_NORMAL),
stretch(DWRITE_FONT_STRETCH_NORMAL),
styleEnum(DWRITE_FONT_STYLE_NORMAL),
hasKerning(false), hasVerticalGlyphs(false), index(0) {
}
FontInfo::~FontInfo() {}
void FontInfo::PrintInfo() const {
std::wcout << L"Font Information:" << std::endl;
std::wcout << L" Family Name: " << familyName << std::endl;
std::wcout << L" Face Name: " << faceName << std::endl;
std::wcout << L" Style: " << style << std::endl;
std::wcout << L" PostScript Name: " << postscriptName << std::endl;
std::wcout << L" Localized Name: " << localizedName << std::endl;
std::wcout << L"\nMetrics:" << std::endl;
std::wcout << L" Ascent: " << ascent << std::endl;
std::wcout << L" Descent: " << descent << std::endl;
std::wcout << L" Line Gap: " << lineGap << std::endl;
std::wcout << L" Cap Height: " << capHeight << std::endl;
std::wcout << L" x Height: " << xHeight << std::endl;
std::wcout << L"\nDesign:" << std::endl;
std::wcout << L" Weight: " << weight << std::endl;
std::wcout << L" Stretch: " << stretch << std::endl;
std::wcout << L" Style: " << styleEnum << std::endl;
std::wcout << L"\nFile Info:" << std::endl;
std::wcout << L" File Path: " << filePath << std::endl;
std::wcout << L" Font Index: " << index << std::endl;
std::wcout << L"\nMetadata:" << std::endl;
std::wcout << L" Designer: " << designer << std::endl;
std::wcout << L" Copyright: " << copyright << std::endl;
std::wcout << L" Version: " << version << std::endl;
std::wcout << L" Trademark: " << trademark << std::endl;
}
cpp
复制代码
#include "FontEnumerator.h"
#include <comdef.h>
#include <vector>
#include <iostream>
#include <dwrite_3.h>
#include <limits>
#pragma comment(lib, "dwrite.lib")
// 辅助函数:安全获取本地化字符串
std::wstring FontEnumerator::GetLocalizedStringSafe(IDWriteLocalizedStrings* pStrings, const wchar_t* preferredLocale ) {
if (!pStrings) return L"";
UINT32 index = 0;
BOOL exists = FALSE;
// 区域查找优先级
const std::vector<std::wstring> localePriority = {
preferredLocale,
L"en-us", // 英语(美国)
L"zh-cn", // 中文(简体)
L"" // 默认第一个
};
HRESULT hr = S_OK;
for (const auto& locale : localePriority) {
if (locale.empty()) {
index = 0;
exists = (pStrings->GetCount() > 0);
break;
}
hr = pStrings->FindLocaleName(locale.c_str(), &index, &exists);
if (SUCCEEDED(hr) && exists) break;
}
if (!exists) return L"";
UINT32 length = 0;
hr = pStrings->GetStringLength(index, &length);
if (FAILED(hr) || length == 0) return L"";
std::wstring buffer(length + 1, L'\0');
hr = pStrings->GetString(index, &buffer[0], length + 1);
if (SUCCEEDED(hr)) {
buffer.resize(length);
return buffer;
}
return L"";
}
FontEnumerator::FontEnumerator()
: pDWriteFactory(nullptr), pSystemFontCollection(nullptr) {
}
FontEnumerator::~FontEnumerator() {
SafeRelease(&pSystemFontCollection);
SafeRelease(&pDWriteFactory);
}
bool FontEnumerator::Initialize() {
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
if (FAILED(hr)) {
_com_error err(hr);
std::wcerr << L"Failed to create DirectWrite factory: " << err.ErrorMessage() << std::endl;
return false;
}
hr = pDWriteFactory->GetSystemFontCollection(&pSystemFontCollection);
if (FAILED(hr)) {
_com_error err(hr);
std::wcerr << L"Failed to get system font collection: " << err.ErrorMessage() << std::endl;
return false;
}
return true;
}
std::vector<FontInfo> FontEnumerator::EnumerateFonts() {
std::vector<FontInfo> fonts;
if (!pSystemFontCollection && !Initialize()) {
return fonts;
}
UINT32 familyCount = pSystemFontCollection->GetFontFamilyCount();
for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
IDWriteFontFamily* pFontFamily = nullptr;
HRESULT hr = pSystemFontCollection->GetFontFamily(familyIndex, &pFontFamily);
if (FAILED(hr)) continue;
UINT32 fontCount = pFontFamily->GetFontCount();
for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
IDWriteFont* pFont = nullptr;
hr = pFontFamily->GetFont(fontIndex, &pFont);
if (FAILED(hr)) {
SafeRelease(&pFontFamily);
continue;
}
FontInfo fontInfo;
GetFontInfo(pFont, fontInfo);
fonts.push_back(fontInfo);
SafeRelease(&pFont);
}
SafeRelease(&pFontFamily);
}
return fonts;
}
void FontEnumerator::GetFontInfo(IDWriteFont* pFont, FontInfo& fontInfo) {
// 获取基本字体信息
GetBasicFontProperties(pFont, fontInfo);
// 获取字体文件信息
IDWriteFontFace* pFontFace = nullptr;
HRESULT hr = pFont->CreateFontFace(&pFontFace);
if (SUCCEEDED(hr)) {
GetFontFaceInfo(pFontFace, fontInfo);
SafeRelease(&pFontFace);
}
}
void FontEnumerator::GetBasicFontProperties(IDWriteFont* pFont, FontInfo& fontInfo) {
// 获取字体度量
DWRITE_FONT_METRICS fontMetrics;
pFont->GetMetrics(&fontMetrics);
fontInfo.ascent = fontMetrics.ascent;
fontInfo.descent = fontMetrics.descent;
fontInfo.lineGap = fontMetrics.lineGap;
fontInfo.capHeight = fontMetrics.capHeight;
fontInfo.xHeight = fontMetrics.xHeight;
fontInfo.underlinePosition = fontMetrics.underlinePosition;
fontInfo.underlineThickness = fontMetrics.underlineThickness;
fontInfo.strikethroughPosition = fontMetrics.strikethroughPosition;
fontInfo.strikethroughThickness = fontMetrics.strikethroughThickness;
fontInfo.weight = pFont->GetWeight();
fontInfo.stretch = pFont->GetStretch();
fontInfo.styleEnum = pFont->GetStyle();
// 获取字体名称信息
IDWriteFontFamily* pFontFamily = nullptr;
if (SUCCEEDED(pFont->GetFontFamily(&pFontFamily))) {
IDWriteLocalizedStrings* pNames = nullptr;
// 家族名称
if (SUCCEEDED(pFontFamily->GetFamilyNames(&pNames))) {
fontInfo.familyName = GetLocalizedStringSafe(pNames);
SafeRelease(&pNames);
}
// 字体面名称
if (SUCCEEDED(pFont->GetFaceNames(&pNames))) {
fontInfo.faceName = GetLocalizedStringSafe(pNames);
fontInfo.style = fontInfo.faceName; // 样式通常与面名相同
SafeRelease(&pNames);
}
// PostScript名称
BOOL exists = FALSE;
if (SUCCEEDED(pFont->GetInformationalStrings(
DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &pNames, &exists)) && exists) {
fontInfo.postscriptName = GetLocalizedStringSafe(pNames);
SafeRelease(&pNames);
}
// 本地化全名
if (SUCCEEDED(pFont->GetInformationalStrings(
DWRITE_INFORMATIONAL_STRING_FULL_NAME, &pNames, &exists)) && exists) {
fontInfo.localizedName = GetLocalizedStringSafe(pNames);
SafeRelease(&pNames);
}
SafeRelease(&pFontFamily);
}
}
void FontEnumerator::GetFontFaceInfo(IDWriteFontFace* pFontFace, FontInfo& fontInfo) {
IDWriteFontFace3* pFontFace3 = nullptr;
HRESULT hr = pFontFace->QueryInterface(__uuidof(IDWriteFontFace3), (void**)&pFontFace3);
if (FAILED(hr)) return;
// 使用智能指针确保资源释放
auto fontFaceDeleter = [](IDWriteFontFace3* p) { if (p) p->Release(); };
std::unique_ptr<IDWriteFontFace3, decltype(fontFaceDeleter)> fontFaceHolder(pFontFace3, fontFaceDeleter);
// 获取字体文件路径
GetFontFilePath(pFontFace3, fontInfo);
// 获取字体元数据
GetFontMetadata(pFontFace3, fontInfo);
// 获取支持的字符集
GetSupportedCharacters(pFontFace3, fontInfo);
}
void FontEnumerator::GetFontFilePath(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo) {
UINT32 numFiles = 0;
HRESULT hr = pFontFace3->GetFiles(&numFiles, nullptr);
if (FAILED(hr) || numFiles == 0) return;
IDWriteFontFile* pFontFile = nullptr;
hr = pFontFace3->GetFiles(&numFiles, &pFontFile);
if (FAILED(hr)) return;
const void* referenceKey = nullptr;
UINT32 referenceKeySize = 0;
hr = pFontFile->GetReferenceKey(&referenceKey, &referenceKeySize);
if (FAILED(hr)) {
SafeRelease(&pFontFile);
return;
}
IDWriteFontFileLoader* pFontFileLoader = nullptr;
hr = pFontFile->GetLoader(&pFontFileLoader);
if (FAILED(hr)) {
SafeRelease(&pFontFile);
return;
}
IDWriteLocalFontFileLoader* pLocalFileLoader = nullptr;
hr = pFontFileLoader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), (void**)&pLocalFileLoader);
if (SUCCEEDED(hr)) {
UINT32 filePathLength = 0;
hr = pLocalFileLoader->GetFilePathLengthFromKey(referenceKey, referenceKeySize, &filePathLength);
if (SUCCEEDED(hr) && filePathLength > 0) {
std::wstring filePath(filePathLength + 1, L'\0');
hr = pLocalFileLoader->GetFilePathFromKey(referenceKey, referenceKeySize, &filePath[0], filePathLength + 1);
if (SUCCEEDED(hr)) {
filePath.resize(filePathLength);
fontInfo.filePath = filePath;
}
}
SafeRelease(&pLocalFileLoader);
}
SafeRelease(&pFontFileLoader);
SafeRelease(&pFontFile);
}
void FontEnumerator::GetFontMetadata(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo) {
// 设计师信息
IDWriteLocalizedStrings* pStrings = nullptr;
BOOL exists = FALSE;
if (SUCCEEDED(pFontFace3->GetInformationalStrings(
DWRITE_INFORMATIONAL_STRING_DESIGNER, &pStrings, &exists)) && exists) {
fontInfo.designer = GetLocalizedStringSafe(pStrings);
SafeRelease(&pStrings);
}
// 版权信息
if (SUCCEEDED(pFontFace3->GetInformationalStrings(
DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &pStrings, &exists)) && exists) {
fontInfo.copyright = GetLocalizedStringSafe(pStrings);
SafeRelease(&pStrings);
}
// 版本信息
if (SUCCEEDED(pFontFace3->GetInformationalStrings(
DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, &pStrings, &exists)) && exists) {
fontInfo.version = GetLocalizedStringSafe(pStrings);
SafeRelease(&pStrings);
}
// 商标信息
if (SUCCEEDED(pFontFace3->GetInformationalStrings(
DWRITE_INFORMATIONAL_STRING_TRADEMARK, &pStrings, &exists)) && exists) {
fontInfo.trademark = GetLocalizedStringSafe(pStrings);
SafeRelease(&pStrings);
}
}void FontEnumerator::GetSupportedCharacters(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo) {
fontInfo.unicodeRanges.clear();
if (!pFontFace3) {
std::cerr << "错误: pFontFace3 是空指针" << std::endl;
return;
}
// 第一次调用:获取所需范围数量
UINT32 rangeCount = 0;
HRESULT hr = pFontFace3->GetUnicodeRanges(0, nullptr, &rangeCount); //第一次调用不能获取返回值
if (rangeCount == 0) {
std::cout << "警告: 字体未声明任何Unicode范围" << std::endl;
return;
}
// 分配足够大的缓冲区
std::vector<DWRITE_UNICODE_RANGE> ranges(rangeCount);
// 第二次调用:获取实际数据
UINT32 actualRangeCount = 0;
hr = pFontFace3->GetUnicodeRanges(rangeCount, ranges.data(), &actualRangeCount);
if (FAILED(hr)) {
_com_error err(hr);
std::cerr << "获取Unicode范围数据失败: " << err.ErrorMessage()
<< " (实际需要大小: " << actualRangeCount
<< ", 分配大小: " << rangeCount << ")" << std::endl;
return;
}
// 检查实际返回数量是否匹配
if (actualRangeCount > rangeCount) {
std::cerr << "警告: 实际范围数量(" << actualRangeCount
<< ")超过预期(" << rangeCount << ")" << std::endl;
ranges.resize(actualRangeCount);
hr = pFontFace3->GetUnicodeRanges(actualRangeCount, ranges.data(), &actualRangeCount);
if (FAILED(hr)) return;
}
// 保存有效数据
fontInfo.unicodeRanges.assign(ranges.begin(), ranges.begin() + actualRangeCount);
}
// 安全释放COM对象
template<class T> void SafeRelease(T** ppT) {
if (*ppT) {
(*ppT)->Release();
*ppT = nullptr;
}
}