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

参考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.mzph.cn/bicheng/72135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

postman--接口测试工具安装和使用教程

postman–接口测试工具 postman是一款支持http协议的接口调试与测试工具&#xff0c;其主要特点就是功能强大&#xff0c;使用简单且易用性好 。 无论是开发人员进行接口调试&#xff0c;还是测试人员做接口测试&#xff0c;postman都是我们的首选工具之一 。 下面先通过一张…

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

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

代码随想录算法训练day64---图论系列8《拓扑排序dijkstra(朴素版)》

代码随想录算法训练 —day64 文章目录 代码随想录算法训练前言一、53. 117. 软件构建—拓扑排序二、47. 参加科学大会---dijkstra&#xff08;朴素版&#xff09;总结 前言 今天是算法营的第64天&#xff0c;希望自己能够坚持下来&#xff01; 今天继续图论part&#xff01;今…

学术小助手智能体

学术小助手&#xff1a;开学季的学术领航员 文心智能体平台AgentBuilder | 想象即现实 文心智能体平台AgentBuilder&#xff0c;是百度推出的基于文心大模型的智能体平台&#xff0c;支持广大开发者根据自身行业领域、应用场景&#xff0c;选取不同类型的开发方式&#xff0c;…

JavaScript 简单类型与复杂类型-复杂类型传参

在JavaScript中&#xff0c;变量根据其存储的数据类型可分为简单类型&#xff08;基本数据类型&#xff09;和复杂类型&#xff08;引用数据类型&#xff09;。理解这两者在函数调用时的行为差异对于编写高效且无误的代码至关重要。本文将专注于探讨复杂类型的参数传递机制&…

L2-043 龙龙送外卖(dfs)

龙龙是“饱了呀”外卖软件的注册骑手&#xff0c;负责送帕特小区的外卖。帕特小区的构造非常特别&#xff0c;都是双向道路且没有构成环 —— 你可以简单地认为小区的路构成了一棵树&#xff0c;根结点是外卖站&#xff0c;树上的结点就是要送餐的地址。 每到中午 12 点&#…

如何基于PyTorch做二次开发

基于PyTorch进行二次开发以实现可视化工程&#xff0c;可以从以下几个方面入手&#xff1a;模型结构可视化、训练过程监控、特征可视化等。以下是一些推荐的GitHub项目&#xff0c;这些项目可以帮助你快速搭建一个可视化的工程环境&#xff1a; ### 1. **PyTorch CNN Visualiz…

本地大模型编程实战(26)用langgraph实现基于SQL数据构建的问答系统(5)

本文将将扩展上一篇文章完成的 langgraph 链&#xff0c;继续使用基于 langgraph 链 &#xff0c;对结构化数据库 SQlite 进行查询的方法。该系统建立以后&#xff0c;我们不需要掌握专业的 SQL 技能&#xff0c;可以用自然语言询问有关数据库中数据的问题并返回答案。主要完善…

【Kubernetes】污点和容忍

一、概述 在 Kubernetes&#xff08;k8s&#xff09;中&#xff0c;污点&#xff08;Taints&#xff09; 是定义在节点上的一种机制&#xff0c;用于拒绝某些 Pod 调度到该节点&#xff0c;除非这些 Pod 具有对应的容忍度&#xff08;Tolerations&#xff09;。污点可以用来控…

【大模型➕知识图谱】大模型结合医疗知识图谱:解锁智能辅助诊疗系统新范式

【大模型➕知识图谱】大模型结合医疗知识图谱:解锁智能辅助诊疗系统新范式 大模型结合医疗知识图谱:解锁智能辅助诊疗系统新范式引言一、系统架构1.1 系统架构图1.2 架构模块说明1.2.1 用户输入1.2.2 大模型(语义理解与意图识别)1.2.3 Agent(问题解析与任务分配)1.2.4 问…

FASIONAD:自适应反馈的类人自动驾驶中快速和慢速思维融合系统

24年11月来自清华、早稻田大学、明尼苏达大学、多伦多大学、厦门大学马来西亚分校、电子科大&#xff08;成都&#xff09;、智平方科技和河南润泰数字科技的论文“FASIONAD : FAst and Slow FusION Thinking Systems for Human-Like Autonomous Driving with Adaptive Feedbac…

【免费】YOLO[笑容]目标检测全过程(yolo环境配置+labelimg数据集标注+目标检测训练测试)

一、yolo环境配置 这篇帖子是我试过的&#xff0c;非常全&#xff0c;很详细【cudaanacondapytorchyolo(ultralytics)】 yolo环境配置 二、labelimg数据集标注 可以参考下面的帖子&#xff0c;不过可能会出现闪退的问题&#xff0c;安装我的流程来吧 2.1 labelimg安装 label…

Linux系统软件管理

systemctl 控制软件启动和关闭 Linux系统很多软件支持使用systemctl命令控制&#xff1a;启动&#xff0c;停止&#xff0c;开启自启。 能被systemctl管理的软件&#xff0c;一般被称为&#xff1a;服务。 语法&#xff1a;systemctl start|stop|status|enable|disable 服务名…

CAN总线通信协议学习1——物理层

首先来看看CAN是怎么产生的&#xff1a;简单理解&#xff0c;CAN就是一种“拥有特别连接方式”的数据传输的总线&#xff0c;其有特定的一些规则。 &#xff08;注&#xff1a;资料及图片来源于知乎博主TOMOCAT。&#xff09; CAN总线的结构 查阅参考文献&#xff0c;OSI标准…

偏移量是什么

在将二维网格映射到一维数组时&#xff0c;偏移量是指在一维数组中 某一行的第一个元素相对于数组起始位置的位置差。对于一个 3 行 4 列的网格&#xff0c;我们使用公式 cur_pos x * n y 来计算二维位置 (x, y) 在一维数组中的索引。 当 x 0 &#xff08;第一行&#xff…

【Mac电脑本地部署Deepseek-r1:详细教程与Openwebui配置指南】

文章目录 前言电脑配置&#xff1a;安装的Deepseek版本&#xff1a;使用的UI框架&#xff1a;体验效果展示&#xff1a;本地部署体验总结 部署过程Ollama部署拉取模型运行模型Openwebui部署运行Ollama服务在Openwebui中配置ollama的服务 后话 前言 deepseek最近火的一塌糊涂&a…

给小白的oracle优化工具,了解一下

有时懒得分析或语句太长&#xff0c;可以尝试用oracle的dbms_sqldiag包进行sql优化&#xff0c; --How To Use DBMS_SQLDIAG To Diagnose Query Performance Issues (Doc ID 1386802.1) --诊断SQL 性能 SET ECHO ON SET LINESIZE 132 SET PAGESIZE 999 SET LONG 999999 SET SER…

YOLO11改进加入ResNet网络

文章目录 1.改进目的2.demo引入2.1代码2.2 结果展示2.3 BottleNeck详解 1.改进目的 原始YOLO11模型训练好以后&#xff0c;检测结果mAP结果很低&#xff0c;视频检测结果很差&#xff0c;于是想到改进网络&#xff0c;这里介绍改进主干网络。 2.demo引入 2.1代码 # File: 2…

Spring MVC流程

SpringMVC启动流程 启动流程父子容器请求处理MultipartFile 解析参数传递返回值处理HandlerInterceptor 启动流程 启动Tomcat解析web.xml创建DispatcherServlet调用DIspatcherServlet的init方法 4.1 创建Spring容器 4.2 发布ContextRefresheEvent 4.3 在OnRefreshed方法中触发…

【大数据】ClickHouse常见的错误及解决方式

ClickHouse 是一款高性能的列式数据库&#xff0c;但在使用过程中难免会遇到一些错误。本文将介绍一些 ClickHouse 常见的错误及其解决方式&#xff0c;帮助您更好地使用 ClickHouse。 1、错误&#xff1a;DB::Exception 错误信息 DB::Exception:Table engine Distributed d…