實現遍歷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.pswp.cn/bicheng/72135.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72135.shtml
英文地址,請注明出處:http://en.pswp.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…