实现遍历Windows所有字体的基本属性

server/2025/3/1 16:55:29/

参考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>using namespace std;
#include <windows.h>
#include <string>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <codecvt>using namespace std;#if defined(_WIN32) || defined(_WIN64)
#define IS_WINDOWS_PLATFORM 1
#else
#define IS_WINDOWS_PLATFORM 0
#endif#if IS_WINDOWS_PLATFORM
using CharNameType = const wchar_t*;
using StringNameType = std::wstring;
#else
using CharNameType = const char*;
using StringNameType = std::string;
#endifclass 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; }// 字符集操作方法/* const std::set<int>& GetCharsets() const { return charsets_; }void AddCharset(int charset) { charsets_.insert(charset); }*/// 修复字符集存储方式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 _WIN32void 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);}
#endifprivate: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) {result.resize(len);transform(data, data + len, result.begin(),[](BYTE c) { return static_cast<wchar_t>(c); });}else if (platform == 3) {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);LOGFONTW lf = { 0 };lf.lfCharSet = DEFAULT_CHARSET; // 必须显式设置才能枚举所有字符集EnumFontFamiliesExW(hdc, &lf, EnumProc, (LPARAM)this, 0);ReleaseDC(nullptr, hdc);BuildIndex();loaded_ = true;}
#if 0void ExportReport(const wstring& filename) const {wofstream file(filename);file.imbue(locale(""));file << L"系统字体报告 (" << fonts_.size() << L" 款)\n";file << L"================================\n";for (const auto& font : fonts_) {file << L"名称: " << font->GetFaceName() << L"\n"<< L"PostScript: " << font->GetPostscriptName() << L"\n"<< L"字符集: ";for (int cs : font->GetCharsets()) {file << cs << L" ";}file << L"\n--------------------------------\n";}}
#elsevoid 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& font : fonts_) {file << L"字体名称: " << font->GetFaceName() << L"\n"<< L"PostScript名称: " << font->GetPostscriptName() << L"\n"<< L"--------------------------------\n"<< L"基本属性:\n"<< L"  基准字号: " << font->GetBaseFont() << L"\n"<< L"  宽度: " << font->GetWidth() << L"\n"<< L"  高度: " << font->GetHeight() << L"\n"<< L"  字重: " << font->GetWeight() << L"\n"<< L"  方向: " << font->GetOrientation() << L"\n"<< L"  倾斜角: " << font->GetEscapement() << L"\n"<< L"  字符间距: " << (font->GetPitchAndFamily() & 0x3) << L"\n"<< L"  字体系列: " << ((font->GetPitchAndFamily() & 0xF0) >> 4) << L"\n"<< L"样式属性:\n"<< L"  斜体: " << (font->IsItalic() ? L"是" : L"否") << L"\n"<< L"  下划线: " << (font->IsUnderline() ? L"是" : L"否") << L"\n"<< L"  删除线: " << (font->IsStrikeOut() ? L"是" : L"否") << L"\n"<< L"字符集 (" << font->GetCharsets().size() << L" 种): ";// 打印字符集详细信息const auto& charsets = font->GetCharsets();for (auto cs : charsets) {file << cs << L" ";}file << L"\n================================\n";}}#endifconst Font* FindFont(const wstring& name) const {wstring key = ToKey(name);auto it = index_.find(key);return (it != index_.end()) ? it->second : 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 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) {auto it = find_if(fonts_.rbegin(), fonts_.rend(), [&](const auto& f) {return ToKey(f->GetFaceName()) == ToKey(newFont->GetFaceName());});if (it != fonts_.rend()) {(*it)->MergeCharsets(newFont->GetCharsets());}else {fonts_.push_back(newFont);}}void BuildIndex() {for (const auto& font : fonts_) {index_[ToKey(font->GetFaceName())] = font.get();}}static wstring ToKey(const wstring& name) {return ToLowerWithoutSpace(name);}vector<shared_ptr<Font>> fonts_;unordered_map<wstring, Font*> index_;bool loaded_ = false;
};int main() {FontManager::Instance().LoadFonts();FontManager::Instance().ExportReport(L"D:/fonts_report.txt");if (auto font = FontManager::Instance().FindFont(L"Arial")) {wcout << L"找到字体: " << font->GetFaceName() << endl;}return 0;
}

http://www.ppmy.cn/server/171586.html

相关文章

综合练习 —— 递归、搜索与回溯算法

目录 一、1863. 找出所有子集的异或总和再求和 - 力扣&#xff08;LeetCode&#xff09; 算法代码&#xff1a; 代码思路 问题分析 核心思想 实现细节 代码解析 初始化 DFS 函数 时间复杂度 空间复杂度 示例运行 输入 运行过程 总结 二、 47. 全排列 II - 力扣&a…

数据结构——二叉树经典习题讲解

各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦 大家好&#xff0c;我们今天来学习java数据结构的二叉树 递归很重要的一些注意事项&#xff1a; 1&#xff1a;递归你能不能掌握在于&#xff1…

HTTPS 与 HTTP 的区别在哪?

HTTP与HTTPS作为互联网数据传输的核心协议&#xff0c;其通信机制与安全特性深刻影响着现代网络应用的可靠性与用户体验。本文将解析两者的通信流程、安全机制及核心差异。 一、HTTP的通信机制 先来看看HTTP是什么吧。 HTTP基于TCP/IP协议栈&#xff0c;采用经典客户端-服务…

lambda表达式,函数式接口,方法引用,Stream流

1.lambda表达式 前提&#xff1a;必须是函数式接口 特殊的匿名内部类&#xff0c;语法更简洁 允许把函数作为一个方法的参数&#xff08;函数作为方法参数传递&#xff09;&#xff0c;将代码像数据一样传递 语法&#xff1a; <函数式接口><变量名>&#xff08…

vscode下载安装教程(附安装包)vscode图文安装教程最新版

文章目录 一、vscode下载二、vscod安装教程1.启动vscode安装程序&#xff1a;2.应对提示&#xff1a;3.接受协议&#xff1a;4.更改vscode安装路径&#xff1a;5.推进安装vscode&#xff1a;6.创建vscode快捷方式&#xff1a;7.开始安装vscode&#xff1a;8.完成vscode安装&…

AI数据分析:用DeepSeek做数据清洗

在当今数据驱动的时代&#xff0c;数据分析已成为企业和个人决策的重要工具。随着人工智能技术的快速发展&#xff0c;AI 驱动的数据分析工具正在改变我们处理和分析数据的方式。本文将着重介绍如何使用 DeepSeek 进行数据清洗。 数据清洗是数据分析的基础&#xff0c;其目的是…

《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》

作者&#xff1a; 周志明 DeepSeek建议JVM书籍首选。 第一部分 走进Java 第1章 走进Java 世界上并没有完美的程序&#xff0c;但我们并不因此而沮丧&#xff0c;因为写程序本来就是一个不断追求完美的过程。 JAVA的优点&#xff0c;摆脱了平台的束缚&#xff0c;实现了一次…

spring注解开发(Spring整合MyBatis——Mapper代理开发模式、(Spring、MyBatis、Jdbc)配置类)(6)

目录 一、纯MyBatis独立开发程序。 &#xff08;1&#xff09;数据库与数据表。 &#xff08;2&#xff09;实体类。 &#xff08;3&#xff09;dao层接口。&#xff08;Mapper代理模式、无SQL映射文件——注解配置映射关系&#xff09; &#xff08;4&#xff09;MyBatis核心配…