参考podofo
#include <windows.h>
#include <string>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <codecvt>
#include <locale>
#include <gdiplus.h>
using namespace std;
class Font {
public:
// 基本属性访问器
int GetBaseFont() const { return base_font_; }
void SetBaseFont(int value) { base_font_ = value; }
int GetWidth() const { return width_; }
void SetWidth(int value) { width_ = value; }
int GetHeight() const { return height_; }
void SetHeight(int value) { height_ = value; }
int GetWeight() const { return weight_; }
void SetWeight(int value) { weight_ = value; }
bool IsItalic() const { return italic_; }
void SetItalic(bool value) { italic_ = value; }
bool IsUnderline() const { return underline_; }
void SetUnderline(bool value) { underline_ = value; }
bool IsStrikeOut() const { return strike_out_; }
void SetStrikeOut(bool value) { strike_out_ = value; }
int GetOrientation() const { return orientation_; }
void SetOrientation(int value) { orientation_ = value; }
int GetEscapement() const { return escapement_; }
void SetEscapement(int value) { escapement_ = value; }
DWORD GetPitchAndFamily() const { return pitch_and_family_; }
void SetPitchAndFamily(DWORD value) { pitch_and_family_ = value; }
void AddCharset(BYTE charset) {
charsets_.insert(static_cast<int>(charset));
}
const set<int>& GetCharsets() const { return charsets_; }
void MergeCharsets(const std::set<int>& other) {
charsets_.insert(other.begin(), other.end());
}
void SetFaceName(const wchar_t* name) {
wcsncpy_s(face_name_, name, _TRUNCATE);
UpdateNormalizedName();
}
const wchar_t* GetFaceName() const { return face_name_; }
void SetPostscriptName(const wstring& name) { postscript_name_ = name; }
const wstring& GetPostscriptName() const { return postscript_name_; }
#ifdef _WIN32
const LOGFONTW& GetLogFont() const {
static LOGFONTW logFont = {};
memset(&logFont, 0, sizeof(LOGFONTW)); // 初始化为零
// 填充 LOGFONTW 的字段
wcsncpy_s(logFont.lfFaceName, face_name_, LF_FACESIZE);
logFont.lfHeight = height_;
logFont.lfWidth = width_;
logFont.lfEscapement = escapement_;
logFont.lfOrientation = orientation_;
logFont.lfWeight = weight_;
logFont.lfItalic = italic_ ? TRUE : FALSE;
logFont.lfUnderline = underline_ ? TRUE : FALSE;
logFont.lfStrikeOut = strike_out_ ? TRUE : FALSE;
logFont.lfCharSet = static_cast<BYTE>(charsets_.empty() ? DEFAULT_CHARSET : *charsets_.begin());
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = DEFAULT_QUALITY;
logFont.lfPitchAndFamily = pitch_and_family_;
return logFont; // 返回静态对象的引用
}
void SetLogFont(const LOGFONTW& lf) {
SetFaceName(lf.lfFaceName);
AddCharset(lf.lfCharSet);
width_ = lf.lfWidth;
height_ = lf.lfHeight;
weight_ = lf.lfWeight;
italic_ = lf.lfItalic;
underline_ = lf.lfUnderline;
strike_out_ = lf.lfStrikeOut;
SetOrientation(lf.lfOrientation);
SetEscapement(lf.lfEscapement);
SetPitchAndFamily(lf.lfPitchAndFamily);
}
#endif
private:
void UpdateNormalizedName() {
normalized_name_.clear();
for (const wchar_t* p = face_name_; *p; ++p) {
if (!wcschr(L" -_", *p)) {
normalized_name_ += towlower(*p);
}
}
}
int base_font_ = 0;
int width_ = 0;
int height_ = 0;
int weight_ = 0;
bool italic_ = false;
bool underline_ = false;
bool strike_out_ = false;
wchar_t face_name_[LF_FACESIZE] = { 0 };
int orientation_ = 0;
int escapement_ = 0;
DWORD pitch_and_family_ = 0;
wstring postscript_name_;
wstring normalized_name_;
std::set<int> charsets_;
};
wstring ToLowerWithoutSpace(const wstring& str) {
wstring result;
result.reserve(str.size());
for (auto ch : str) {
if (!wcschr(L" _-", ch)) {
result += towlower(ch);
}
}
return result;
}
class TTFontParser {
public:
static wstring GetPostScriptName(HDC hdc) {
vector<BYTE> table = GetFontTable(hdc, 'eman');
return table.empty() ? L"" : ParseNameTable(table, 6);
}
private:
static vector<BYTE> GetFontTable(HDC hdc, DWORD tag) {
DWORD size = ::GetFontData(hdc, tag, 0, nullptr, 0);
if (size == GDI_ERROR) return {};
vector<BYTE> buffer(size);
return (::GetFontData(hdc, tag, 0, buffer.data(), size) == size) ? buffer : vector<BYTE>();
}
static wstring ParseNameTable(const vector<BYTE>& table, WORD targetID) {
if (table.size() < 6) return L"";
auto readU16 = [&](size_t offset) {
return static_cast<WORD>((table[offset] << 8) | table[offset + 1]);
};
const WORD count = readU16(2);
const WORD strOffset = readU16(4);
for (WORD i = 0; i < count; ++i) {
size_t record = 6 + i * 12;
if (readU16(record + 6) != targetID) continue;
const WORD platformID = readU16(record);
const WORD encodingID = readU16(record + 2);
const WORD length = readU16(record + 8);
const WORD offset = readU16(record + 10);
if (IsValidEncoding(platformID, encodingID)) {
return DecodeString(&table[strOffset + offset], length, platformID);
}
}
return L"";
}
static bool IsValidEncoding(WORD platform, WORD encoding) {
return (platform == 1 && encoding == 0) || (platform == 3 && encoding == 1);
}
static wstring DecodeString(const BYTE* data, size_t len, WORD platform) {
wstring result;
if (platform == 1) { // Single-byte encoding
result.resize(len);
transform(data, data + len, result.begin(), [](BYTE c) { return static_cast<wchar_t>(c); });
}
else if (platform == 3) { // UTF-16 encoding
result.resize(len / 2);
for (size_t i = 0; i < len / 2; ++i) {
result[i] = (data[i * 2] << 8) | data[i * 2 + 1];
}
}
return result;
}
};
class FontManager {
public:
static FontManager& Instance() {
static FontManager instance;
return instance;
}
void LoadFonts() {
if (loaded_) return;
HDC hdc = CreateCompatibleDC(nullptr);
HGDIOBJ oldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
LOGFONTW lf = { 0 };
lf.lfCharSet = DEFAULT_CHARSET; // 必须显式设置才能枚举所有字符集
EnumFontFamiliesExW(hdc, &lf, EnumProc, (LPARAM)this, 0);
SelectObject(hdc, oldFont);
DeleteDC(hdc);
loaded_ = true;
}
void ExportReport(const wstring& filename) const {
wofstream file(filename);
file.imbue(locale(""));
file << L"完整的系统字体报告\n";
file << L"================================\n";
file << L"总字体数: " << fonts_.size() << L"\n\n";
for (const auto& pair : fonts_) {
const auto& font = pair.second;
file << L"字体名称: " << font->GetFaceName() << L"\n";
file << L"PostScript名称: " << font->GetPostscriptName() << L"\n";
file << L"--------------------------------\n";
file << L"基本属性:\n";
file << L" 基准字号: " << font->GetBaseFont() << L"\n";
file << L" 宽度: " << font->GetWidth() << L"\n";
file << L" 高度: " << font->GetHeight() << L"\n";
file << L" 字重: " << font->GetWeight() << L"\n";
file << L" 方向: " << font->GetOrientation() << L"\n";
file << L" 倾斜角: " << font->GetEscapement() << L"\n";
file << L" 字符间距: " << (font->GetPitchAndFamily() & 0x3) << L"\n";
file << L" 字体系列: " << ((font->GetPitchAndFamily() & 0xF0) >> 4) << L"\n";
file << L"样式属性:\n";
file << L" 斜体: " << (font->IsItalic() ? L"是" : L"否") << L"\n";
file << L" 下划线: " << (font->IsUnderline() ? L"是" : L"否") << L"\n";
file << L" 删除线: " << (font->IsStrikeOut() ? L"是" : L"否") << L"\n";
file << L"字符集 (" << font->GetCharsets().size() << L" 种): ";
const auto& charsets = font->GetCharsets();
for (auto cs : charsets) {
file << cs << L" ";
}
file << L"\n\n";
}
}
const Font* FindFont(const wstring& name, bool fuzzyMatch = false) const {
wstring key = ToKey(name);
if (!fuzzyMatch) {
auto it = fonts_.find(key);
return (it != fonts_.end()) ? it->second.get() : nullptr;
}
// 模糊匹配
for (const auto& pair : fonts_) {
if (pair.first.find(key) != wstring::npos) {
return pair.second.get();
}
}
return nullptr;
}
private:
static int CALLBACK EnumProc(const LOGFONTW* lf, const TEXTMETRICW*, DWORD, LPARAM param) {
if (lf->lfFaceName[0] == L'@') return TRUE;
FontManager* self = reinterpret_cast<FontManager*>(param);
auto font = make_shared<Font>();
font->SetLogFont(*lf);
// 使用共享的 HDC 获取 PostScript 名称
HDC hdc = GetDC(nullptr);
HFONT hFont = CreateFontIndirectW(lf);
HGDIOBJ old = SelectObject(hdc, hFont);
font->SetPostscriptName(TTFontParser::GetPostScriptName(hdc));
SelectObject(hdc, old);
DeleteObject(hFont);
ReleaseDC(nullptr, hdc);
self->AddFont(font);
return TRUE;
}
void AddFont(shared_ptr<Font> newFont) {
wstring key = ToKey(newFont->GetFaceName());
if (fonts_.count(key) > 0) {
fonts_[key]->MergeCharsets(newFont->GetCharsets());
}
else {
fonts_[key] = newFont;
}
}
static wstring ToKey(const wstring& name) {
return ToLowerWithoutSpace(name);
}
unordered_map<wstring, shared_ptr<Font>> fonts_;
bool loaded_ = false;
};
int main() {
FontManager::Instance().LoadFonts();
// 查找字体
if (auto font = FontManager::Instance().FindFont(L"Arial")) {
wcout << L"找到字体: " << font->GetFaceName() << endl;
// 获取 LOGFONTW 数据
const LOGFONTW& logFont = font->GetLogFont();
wcout << L"LOGFONTW 高度: " << logFont.lfHeight << endl;
wcout << L"LOGFONTW 字体名称: " << logFont.lfFaceName << endl;
}
// 导出字体报告
FontManager::Instance().ExportReport(L"D:/font_report.txt");
return 0;
}