Windows获取字体文件

ops/2025/2/26 19:08:29/
// 包含必要的头文件
#include <string>
#include <set>
#include <vector>
#include <iostream>
#include <filesystem>
#include <windows.h>
#include <fstream> // 用于文件操作
#include <algorithm> // 确保包含 std::min 的声明using namespace std;// 函数声明
std::unique_ptr<std::string> GetWinFontData(std::wstring font_name); // 获取指定字体的字节数据
std::unique_ptr<std::string> GetWinFontData(const LOGFONTW& infont); // 获取指定字体的字节数据,并返回一个指向该数据的 `std::unique_ptr<std::string>`
bool GetWinFontData(std::string& buffer, HDC hdc, HFONT hf); // 辅助函数,用于从指定的字体对象中提取字体数据
void GetFontDataTTC(std::string& buffer, const std::string& file_buffer, const std::string& ttc_buffer); // 处理 TrueType 集合(TTC)数据,提取并重组字体表
void SaveFontToFile(const std::string& font_data, const std::wstring& font_name); // 将字体数据保存到文件
void ListInstalledFonts(); // 列出所有已安装字体// 获取指定字体的字节数据。
std::unique_ptr<std::string> GetWinFontData(std::wstring font_name)
{// 检查字体名称长度是否超出限制if (font_name.length() >= LF_FACESIZE)return nullptr;// 初始化 LOGFONTW 结构体LOGFONTW lf = {};memset(lf.lfFaceName, 0, LF_FACESIZE * sizeof(wchar_t));wcsncpy_s(lf.lfFaceName, font_name.c_str(), (std::min)(font_name.length(), (size_t)(LF_FACESIZE - 1)));// 调用辅助函数获取字体数据return GetWinFontData(lf);
}// 获取指定字体的字节数据,并返回一个指向该数据的 `std::unique_ptr<std::string>`。
std::unique_ptr<std::string> GetWinFontData(const LOGFONTW& infont)
{bool success = false;std::string buffer;buffer.clear();// 创建兼容设备上下文 (HDC)HDC hdc = ::CreateCompatibleDC(nullptr);// 根据字体描述创建字体对象 (HFONT)HFONT hf = CreateFontIndirectW(&infont);// 如果字体对象创建成功,则提取字体数据if (hf != nullptr){success = GetWinFontData(buffer, hdc, hf);DeleteObject(hf); // 删除字体对象}ReleaseDC(0, hdc); // 释放设备上下文// 如果提取成功,返回字体数据;否则返回空指针if (success)return std::make_unique<std::string>(std::move(buffer));elsereturn nullptr;
}// 辅助函数,用于从指定的字体对象中提取字体数据。
bool GetWinFontData(std::string& buffer, HDC hdc, HFONT hf)
{HGDIOBJ oldFont = SelectObject(hdc, hf); // 选择字体到设备上下文中bool sucess = false;constexpr DWORD ttcf_const = 0x66637474; // TTC 文件标识符// 获取字体数据的长度unsigned fileLen = GetFontData(hdc, 0, 0, nullptr, 0);unsigned ttcLen = GetFontData(hdc, ttcf_const, 0, nullptr, 0);// 如果字体数据长度有效,则提取数据if (fileLen != GDI_ERROR){if (ttcLen == GDI_ERROR) // 如果不是 TTC 文件{buffer.resize(fileLen); // 分配缓冲区sucess = GetFontData(hdc, 0, 0, const_cast<char*>(buffer.data()), (DWORD)fileLen) != GDI_ERROR;}else // 如果是 TTC 文件{std::string fileBuffer;fileBuffer.resize(fileLen);// 提取 TTC 文件的基本信息if (GetFontData(hdc, 0, 0, const_cast<char*>(fileBuffer.data()), fileLen) == GDI_ERROR){sucess = false;goto Exit;}std::string ttcBuffer;ttcBuffer.resize(ttcLen);// 提取 TTC 文件的具体数据if (GetFontData(hdc, ttcf_const, 0, const_cast<char*>(ttcBuffer.data()), ttcLen) == GDI_ERROR){sucess = false;goto Exit;}// 调用函数处理 TTC 数据GetFontDataTTC(buffer, fileBuffer, ttcBuffer);sucess = true;}}Exit:SelectObject(hdc, oldFont); // 恢复原始字体return sucess;
}// 处理 TrueType 集合(TTC)数据,提取并重组字体表。
void GetFontDataTTC(std::string& buffer, const std::string& file_buffer, const std::string& ttc_buffer)
{uint16_t numTables = _byteswap_ushort(*(uint16_t*)(file_buffer.data() + 4)); // 获取表的数量unsigned outLen = 12 + 16 * numTables; // 计算输出缓冲区大小const char* entry = file_buffer.data() + 12; // 指向表条目// 遍历每个表条目,计算总大小for (unsigned i = 0; i < numTables; i++){uint32_t length = _byteswap_ulong(*(uint32_t*)(entry + 12)); // 获取表长度length = (length + 3) & ~3; // 对齐到 4 字节边界entry += 16; // 移动到下一个表条目outLen += length;}buffer.resize(outLen); // 分配输出缓冲区memcpy(const_cast<char*>(buffer.data()), file_buffer.data(), 12 + 16 * numTables); // 复制表头信息uint32_t dstDataOffset = 12 + 16 * numTables; // 输出数据偏移量const char* srcEntry = file_buffer.data() + 12; // 输入表条目指针char* dstEntry = const_cast<char*>(buffer.data()) + 12; // 输出表条目指针// 遍历每个表条目,复制数据for (unsigned i = 0; i < numTables; i++){uint32_t offset = _byteswap_ulong(*(uint32_t*)(srcEntry + 8)); // 获取表偏移量uint32_t length = _byteswap_ulong(*(uint32_t*)(srcEntry + 12)); // 获取表长度length = (length + 3) & ~3; // 对齐到 4 字节边界*(uint32_t*)(dstEntry + 8) = _byteswap_ulong(dstDataOffset); // 更新输出表偏移量memcpy(const_cast<char*>(buffer.data()) + dstDataOffset, ttc_buffer.data() + offset, length); // 复制表数据dstDataOffset += length; // 更新输出数据偏移量srcEntry += 16; // 移动到下一个输入表条目dstEntry += 16; // 移动到下一个输出表条目}
}// 将字体数据保存到文件。
void SaveFontToFile(const std::string& font_data, const std::wstring& font_name)
{try{wstring output_path = L"D:\\Unit_Test\\" + font_name + L".ttf"; // 构造输出文件路径CreateDirectoryW(L"output", NULL); // 创建输出目录(如果不存在)ofstream file(output_path, ios::binary); // 打开文件以二进制模式写入if (!file.is_open()){wcerr << L"无法创建文件: " << output_path << endl; // 输出错误信息return;}file.write(font_data.data(), font_data.size()); // 写入字体数据file.close(); // 关闭文件wcout << L"字体已保存到: " << output_path << endl; // 输出成功信息}catch (const exception& e){cerr << "Error saving font file: " << e.what() << endl; // 捕获并输出异常信息}
}// 列出所有已安装字体。
void ListInstalledFonts()
{HDC hdc = GetDC(NULL); // 获取屏幕设备上下文LOGFONTW lf = { 0 }; // 初始化字体描述结构体lf.lfCharSet = DEFAULT_CHARSET; // 设置默认字符集// 枚举所有字体EnumFontFamiliesExW(hdc, &lf, [](const LOGFONTW* lf, const TEXTMETRICW*, DWORD, LPARAM lParam) -> int {wcout << L"Font: " << lf->lfFaceName << endl; // 输出字体名称return 1;}, 0, 0);ReleaseDC(NULL, hdc); // 释放设备上下文
}// 主函数
int main()
{ListInstalledFonts(); // 列出所有已安装字体// 测试字体提取auto data1 = GetWinFontData(L"Arial"); // 提取 Arial 字体数据if (data1)SaveFontToFile(*data1, L"Arial"); // 保存 Arial 字体数据auto data2 = GetWinFontData(L"Batang"); // 提取 Batang 字体数据if (data2)SaveFontToFile(*data2, L"Batang"); // 保存 Batang 字体数据return 0;
}

http://www.ppmy.cn/ops/161475.html

相关文章

flink系列之:使用flink cdc3从mysql数据库同步数据到doris和starrocks

flink系列之&#xff1a;使用flink cdc3从mysql数据库同步数据到doris和starrocks 一、下载部署flink二、下载部署flink cdc3三、下载mysql-connector-java到flink和flink cdc的lib目录四、flink设置checkpoint支持增量同步数据五、mysql到doris和starrocks的yaml配置文件六、启…

眼见不一定为实之MySQL中的不可见字符

目录 前言 一、问题的由来 1、需求背景 2、数据表结构 二、定位问题 1、初步的问题 2、编码是否有问题 3、依然回到字符本身 三、深入字符本身 1、回归本质 2、数据库解决之道 3、代码层解决 四、总结 前言 在开始今天的博客内容之前&#xff0c;正在看博客的您先…

HarmonyOS Design 介绍

HarmonyOS Design 介绍 文章目录 HarmonyOS Design 介绍一、HarmonyOS Design 是什么&#xff1f;1. 设计系统&#xff08;Design System&#xff09;2. UI 框架的支持3. 设计工具和资源4. 开发指南5. 与其他设计系统的对比总结 二、HarmonyOS Design 特点 | 应用场景1. Harmon…

改进的Siddon算法与原算法的区别及具体改进

1. 算法原理 原Siddon算法&#xff1a; 基本原理&#xff1a;Siddon算法是一种射线驱动模型&#xff08;RDM&#xff09;&#xff0c;用于计算射线通过像素或体素空间的精确路径。它通过计算射线与每个像素或体素的交点&#xff0c;来确定射线在每个像素或体素内的长度&#xf…

ElasticSearch公共方法封装

业务场景 1、RestClientBuilder初始化&#xff08;同时支持单机与集群&#xff09; 2、发送ES查询请求公共方法封装&#xff08;支持sql、kql、代理访问、集群访问、鉴权支持&#xff09; 3、判断ES索引是否存在&#xff08;/_cat/indices/${indexName}&#xff09; 4、判断ES…

前端+nodejs+mysql实现前后端联通

创建项目 目录结构 创建项目 npm init 初始化项目 一路回车即可 当有 package.json这个文件的时候就相当于已经构建完毕 3. 配置package.json文件 {"name": "yes","version": "1.0.0","description": "",&quo…

数据结构(陈越,何钦铭) 第四讲 树(中)

4.1 二叉搜索树 4.1.1 二叉搜索树及查找 Position Find(ElementTyoe X,BinTree BST){if(!BST){return NULL;}if(X>BST->Data){return Find(X,BST->Right)}else if(X<BST->Data){return Find(X,BST->Left)}else{return BST;} } Position IterFind(ElementTyp…

5G网络切片辨析(eMBB,mMTC,uRLLC)

URLLC有三大应用场景&#xff0c;分别是eMBB&#xff08;增强型移动宽带&#xff09;、uRLLC&#xff08;高可靠低延时通信&#xff09;和mMTC&#xff08;海量机器通信&#xff09;。 增强型移动宽带&#xff08;eMBB&#xff09;&#xff1a;需要关注峰值速率&#xff0c;容…