Windows下筛选具备EMBED_EDITABLE权限的TrueType字体嵌入PDF的技术问询
我来帮你梳理下如何实现这个需求——枚举系统中允许编辑嵌入(EMBED_EDITABLE)的TrueType字体并填充到下拉组合框里,这在PDF嵌入场景中非常实用:
实现方案拆解
核心要做两步:先筛选出TrueType字体,再验证它的嵌入权限是否支持EMBED_EDITABLE,符合条件的才加入下拉框。
完整代码实现
1. 枚举回调函数(核心判断逻辑)
#include <windows.h> #include <wingdi.h> BOOL CALLBACK WFonteCombo::EnumFontProc(LPLOGFONT lplf, LPTEXTMETRIC lptm, DWORD dwType, LPARAM lpData) { // 第一步:过滤非TrueType字体 if (!(dwType & TRUETYPE_FONTTYPE)) return TRUE; // 继续枚举下一个 WFonteCombo* pCombo = reinterpret_cast<WFonteCombo*>(lpData); if (!pCombo) return FALSE; // 创建临时DC用于读取字体嵌入权限信息 HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL); if (!hDC) return TRUE; // 选入当前枚举到的字体 HFONT hFont = CreateFontIndirect(lplf); HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject(hDC, hFont)); // 读取字体OS/2表中的fsType字段(存储嵌入权限) DWORD embeddable = GetFontData(hDC, 0x0000, 0, NULL, 0); if (embeddable != GDI_ERROR) { BYTE fsType[2] = {0}; // fsType字段在OS/2表的第38字节位置(十进制) if (GetFontData(hDC, 0x0000, 38, fsType, 2) == 2) { DWORD fsTypeValue = (static_cast<DWORD>(fsType[1]) << 8) | fsType[0]; // 关键判断:EMBED_EDITABLE要求fsType的第1位(0x0002)未被设置 // 即该位未标记时,字体允许编辑嵌入 if (!(fsTypeValue & 0x0002)) { // 将符合条件的字体名称添加到下拉框 pCombo->AddString(lplf->lfFaceName); } } } // 清理资源,避免内存泄漏 SelectObject(hDC, hOldFont); DeleteObject(hFont); DeleteDC(hDC); return TRUE; // 继续枚举剩余字体 }
2. 触发枚举的调用代码
void WFonteCombo::LoadEditableTrueTypeFonts() { this->ResetContent(); // 先清空下拉框原有内容 HDC hDC = ::GetDC(NULL); if (!hDC) return; LOGFONT lf = {0}; lf.lfCharSet = DEFAULT_CHARSET; // 枚举所有字符集的字体,需特定字符集可修改此处 // 启动字体枚举 EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)EnumFontProc, reinterpret_cast<LPARAM>(this), 0); ::ReleaseDC(NULL, hDC); }
关键细节说明
- 嵌入权限判断规则:TrueType字体的嵌入权限由
fsType字段控制,EMBED_EDITABLE对应的是“不禁止编辑嵌入”——也就是fsType的0x0002位未被设置。如果该位被标记,说明字体不允许编辑嵌入,无法用于PDF的可编辑嵌入场景。 - 资源管理:枚举过程中创建的临时DC、字体对象一定要及时释放,否则会造成GDI资源泄漏。
- 字符集筛选:如果你的应用只需要特定字符集的字体(比如中文GB2312),可以把
LOGFONT的lfCharSet改成GB2312_CHARSET,缩小枚举范围。
内容的提问来源于stack exchange,提问作者Penachia
相关产品推荐
相关产品推荐

