Windows DirectWrite接口 遍历字体信息

FontInfo.h

cpp 复制代码
#pragma once
#include <string>
#include <vector>
#include <dwrite.h>
#include <comdef.h>
#include <vector>
#include <iostream>
#include <dwrite_3.h>
#include <limits> 
#pragma comment(lib, "dwrite.lib")
class FontInfo {
public:
	FontInfo();
	~FontInfo();

	// 字体基本信息
	std::wstring familyName;       // 字体家族名称
	std::wstring faceName;         // 字体面名称
	std::wstring postscriptName;   // PostScript名称
	std::wstring style;            // 样式 (常规、斜体、粗体等)
	std::wstring localizedName;    // 本地化名称

	// 字体度量信息
	float ascent;                  // 基线到最高点的距离
	float descent;                 // 基线到最低点的距离
	float lineGap;                 // 行间距
	float capHeight;               // 大写字母高度
	float xHeight;                 // 小写字母x高度
	float underlinePosition;       // 下划线位置
	float underlineThickness;      // 下划线粗细
	float strikethroughPosition;   // 删除线位置
	float strikethroughThickness;  // 删除线粗细

	// 字体设计信息
	DWRITE_FONT_WEIGHT weight;     // 字体粗细
	DWRITE_FONT_STRETCH stretch;   // 字体拉伸
	DWRITE_FONT_STYLE styleEnum;   // 字体样式枚举

	// 字体支持特性
	bool hasKerning;               // 是否支持字距调整
	bool hasVerticalGlyphs;        // 是否支持垂直排版

	// 字符集信息
	//std::vector<UINT32> codePoints; // 支持的Unicode码点
	 // 改为存储 Unicode 范围而非单个码点
	std::vector<DWRITE_UNICODE_RANGE> unicodeRanges;

	// 文件信息
	std::wstring filePath;         // 字体文件路径
	UINT32 index;                  // 字体集合中的索引

	// 其他元数据
	std::wstring designer;         // 设计师
	std::wstring copyright;        // 版权信息
	std::wstring version;          // 版本信息
	std::wstring trademark;        // 商标信息

	// 打印字体信息
	void PrintInfo() const;
};

FontInfo.cpp

cpp 复制代码
#include "FontInfo.h"
#include <iostream>

FontInfo::FontInfo()
	: ascent(0), descent(0), lineGap(0), capHeight(0), xHeight(0),
	underlinePosition(0), underlineThickness(0),
	strikethroughPosition(0), strikethroughThickness(0),
	weight(DWRITE_FONT_WEIGHT_NORMAL),
	stretch(DWRITE_FONT_STRETCH_NORMAL),
	styleEnum(DWRITE_FONT_STYLE_NORMAL),
	hasKerning(false), hasVerticalGlyphs(false), index(0) {
}

FontInfo::~FontInfo() {}

void FontInfo::PrintInfo() const {
	std::wcout << L"Font Information:" << std::endl;
	std::wcout << L"  Family Name: " << familyName << std::endl;
	std::wcout << L"  Face Name: " << faceName << std::endl;
	std::wcout << L"  Style: " << style << std::endl;
	std::wcout << L"  PostScript Name: " << postscriptName << std::endl;
	std::wcout << L"  Localized Name: " << localizedName << std::endl;

	std::wcout << L"\nMetrics:" << std::endl;
	std::wcout << L"  Ascent: " << ascent << std::endl;
	std::wcout << L"  Descent: " << descent << std::endl;
	std::wcout << L"  Line Gap: " << lineGap << std::endl;
	std::wcout << L"  Cap Height: " << capHeight << std::endl;
	std::wcout << L"  x Height: " << xHeight << std::endl;

	std::wcout << L"\nDesign:" << std::endl;
	std::wcout << L"  Weight: " << weight << std::endl;
	std::wcout << L"  Stretch: " << stretch << std::endl;
	std::wcout << L"  Style: " << styleEnum << std::endl;

	std::wcout << L"\nFile Info:" << std::endl;
	std::wcout << L"  File Path: " << filePath << std::endl;
	std::wcout << L"  Font Index: " << index << std::endl;

	std::wcout << L"\nMetadata:" << std::endl;
	std::wcout << L"  Designer: " << designer << std::endl;
	std::wcout << L"  Copyright: " << copyright << std::endl;
	std::wcout << L"  Version: " << version << std::endl;
	std::wcout << L"  Trademark: " << trademark << std::endl;
}

FontEnumerator.h

cpp 复制代码
// FontEnumerator.h
#pragma once
#include "FontInfo.h"
#include <string>
#include <vector>
#include <dwrite.h>
#include <dwrite_3.h>
//
//class FontInfo {
//public:
//    // 字体基本信息
//    std::wstring familyName;       // 字体家族名称
//    std::wstring faceName;         // 字体面名称
//    std::wstring postscriptName;   // PostScript名称
//    std::wstring style;            // 样式 (常规、斜体、粗体等)
//    std::wstring localizedName;    // 本地化名称
//
//    // 字体度量信息
//    float ascent = 0;              // 基线到最高点的距离
//    float descent = 0;             // 基线到最低点的距离
//    float lineGap = 0;             // 行间距
//    float capHeight = 0;           // 大写字母高度
//    float xHeight = 0;             // 小写字母x高度
//    float underlinePosition = 0;   // 下划线位置
//    float underlineThickness = 0;  // 下划线粗细
//    float strikethroughPosition = 0;   // 删除线位置
//    float strikethroughThickness = 0;  // 删除线粗细
//
//    // 字体设计信息
//    DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL;     // 字体粗细
//    DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL;  // 字体拉伸
//    DWRITE_FONT_STYLE styleEnum = DWRITE_FONT_STYLE_NORMAL;   // 字体样式枚举
//
//    // 字体支持特性
//    bool hasKerning = false;               // 是否支持字距调整
//    bool hasVerticalGlyphs = false;        // 是否支持垂直排版
//
//    // 字符集信息
//    std::vector<UINT32> codePoints;        // 支持的Unicode码点
//
//    // 文件信息
//    std::wstring filePath;                // 字体文件路径
//    UINT32 index = 0;                     // 字体集合中的索引
//
//    // 其他元数据
//    std::wstring designer;                // 设计师
//    std::wstring copyright;               // 版权信息
//    std::wstring version;                // 版本信息
//    std::wstring trademark;               // 商标信息
//
//    void PrintInfo() const;
//};

class FontEnumerator {
public:
    FontEnumerator();
    ~FontEnumerator();

    bool Initialize();
    std::vector<FontInfo> EnumerateFonts();

private:
    IDWriteFactory* pDWriteFactory;
    IDWriteFontCollection* pSystemFontCollection;

    // 核心功能方法
    void GetFontInfo(IDWriteFont* pFont, FontInfo& fontInfo);
    void GetBasicFontProperties(IDWriteFont* pFont, FontInfo& fontInfo);
    void GetFontFaceInfo(IDWriteFontFace* pFontFace, FontInfo& fontInfo);

    // 详细信息获取方法
    void GetFontFilePath(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo);
    void GetFontMetadata(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo);
    void GetSupportedCharacters(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo);

    // 辅助方法
    static std::wstring GetLocalizedStringSafe(IDWriteLocalizedStrings* pStrings,
        const wchar_t* preferredLocale = L"en-us");

    // COM对象安全释放
    template<class T> static void SafeRelease(T** ppT) {
        if (*ppT) {
            (*ppT)->Release();
            *ppT = nullptr;
        }
    }
};

FontEnumerator.cpp

cpp 复制代码
#include "FontEnumerator.h"
#include <comdef.h>
#include <vector>
#include <iostream>
#include <dwrite_3.h>
#include <limits> 
#pragma comment(lib, "dwrite.lib")

// 辅助函数:安全获取本地化字符串
std::wstring FontEnumerator::GetLocalizedStringSafe(IDWriteLocalizedStrings* pStrings, const wchar_t* preferredLocale ) {
    if (!pStrings) return L"";

    UINT32 index = 0;
    BOOL exists = FALSE;

    // 区域查找优先级
    const std::vector<std::wstring> localePriority = {
        preferredLocale,
        L"en-us",    // 英语(美国)
        L"zh-cn",    // 中文(简体)
        L""          // 默认第一个
    };

    HRESULT hr = S_OK;
    for (const auto& locale : localePriority) {
        if (locale.empty()) {
            index = 0;
            exists = (pStrings->GetCount() > 0);
            break;
        }

        hr = pStrings->FindLocaleName(locale.c_str(), &index, &exists);
        if (SUCCEEDED(hr) && exists) break;
    }

    if (!exists) return L"";

    UINT32 length = 0;
    hr = pStrings->GetStringLength(index, &length);
    if (FAILED(hr) || length == 0) return L"";

    std::wstring buffer(length + 1, L'\0');
    hr = pStrings->GetString(index, &buffer[0], length + 1);
    if (SUCCEEDED(hr)) {
        buffer.resize(length);
        return buffer;
    }

    return L"";
}

FontEnumerator::FontEnumerator()
    : pDWriteFactory(nullptr), pSystemFontCollection(nullptr) {
}

FontEnumerator::~FontEnumerator() {
    SafeRelease(&pSystemFontCollection);
    SafeRelease(&pDWriteFactory);
}

bool FontEnumerator::Initialize() {
    HRESULT hr = DWriteCreateFactory(
        DWRITE_FACTORY_TYPE_SHARED,
        __uuidof(IDWriteFactory),
        reinterpret_cast<IUnknown**>(&pDWriteFactory)
    );

    if (FAILED(hr)) {
        _com_error err(hr);
        std::wcerr << L"Failed to create DirectWrite factory: " << err.ErrorMessage() << std::endl;
        return false;
    }

    hr = pDWriteFactory->GetSystemFontCollection(&pSystemFontCollection);
    if (FAILED(hr)) {
        _com_error err(hr);
        std::wcerr << L"Failed to get system font collection: " << err.ErrorMessage() << std::endl;
        return false;
    }

    return true;
}

std::vector<FontInfo> FontEnumerator::EnumerateFonts() {
    std::vector<FontInfo> fonts;

    if (!pSystemFontCollection && !Initialize()) {
        return fonts;
    }

    UINT32 familyCount = pSystemFontCollection->GetFontFamilyCount();

    for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
        IDWriteFontFamily* pFontFamily = nullptr;
        HRESULT hr = pSystemFontCollection->GetFontFamily(familyIndex, &pFontFamily);
        if (FAILED(hr)) continue;

        UINT32 fontCount = pFontFamily->GetFontCount();

        for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
            IDWriteFont* pFont = nullptr;
            hr = pFontFamily->GetFont(fontIndex, &pFont);
            if (FAILED(hr)) {
                SafeRelease(&pFontFamily);
                continue;
            }

            FontInfo fontInfo;
            GetFontInfo(pFont, fontInfo);
            fonts.push_back(fontInfo);

            SafeRelease(&pFont);
        }

        SafeRelease(&pFontFamily);
    }

    return fonts;
}

void FontEnumerator::GetFontInfo(IDWriteFont* pFont, FontInfo& fontInfo) {
    // 获取基本字体信息
    GetBasicFontProperties(pFont, fontInfo);

    // 获取字体文件信息
    IDWriteFontFace* pFontFace = nullptr;
    HRESULT hr = pFont->CreateFontFace(&pFontFace);
    if (SUCCEEDED(hr)) {
        GetFontFaceInfo(pFontFace, fontInfo);
        SafeRelease(&pFontFace);
    }
}

void FontEnumerator::GetBasicFontProperties(IDWriteFont* pFont, FontInfo& fontInfo) {
    // 获取字体度量
    DWRITE_FONT_METRICS fontMetrics;
    pFont->GetMetrics(&fontMetrics);

    fontInfo.ascent = fontMetrics.ascent;
    fontInfo.descent = fontMetrics.descent;
    fontInfo.lineGap = fontMetrics.lineGap;
    fontInfo.capHeight = fontMetrics.capHeight;
    fontInfo.xHeight = fontMetrics.xHeight;
    fontInfo.underlinePosition = fontMetrics.underlinePosition;
    fontInfo.underlineThickness = fontMetrics.underlineThickness;
    fontInfo.strikethroughPosition = fontMetrics.strikethroughPosition;
    fontInfo.strikethroughThickness = fontMetrics.strikethroughThickness;

    fontInfo.weight = pFont->GetWeight();
    fontInfo.stretch = pFont->GetStretch();
    fontInfo.styleEnum = pFont->GetStyle();

    // 获取字体名称信息
    IDWriteFontFamily* pFontFamily = nullptr;
    if (SUCCEEDED(pFont->GetFontFamily(&pFontFamily))) {
        IDWriteLocalizedStrings* pNames = nullptr;

        // 家族名称
        if (SUCCEEDED(pFontFamily->GetFamilyNames(&pNames))) {
            fontInfo.familyName = GetLocalizedStringSafe(pNames);
            SafeRelease(&pNames);
        }

        // 字体面名称
        if (SUCCEEDED(pFont->GetFaceNames(&pNames))) {
            fontInfo.faceName = GetLocalizedStringSafe(pNames);
            fontInfo.style = fontInfo.faceName; // 样式通常与面名相同
            SafeRelease(&pNames);
        }

        // PostScript名称
        BOOL exists = FALSE;
        if (SUCCEEDED(pFont->GetInformationalStrings(
            DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &pNames, &exists)) && exists) {
            fontInfo.postscriptName = GetLocalizedStringSafe(pNames);
            SafeRelease(&pNames);
        }

        // 本地化全名
        if (SUCCEEDED(pFont->GetInformationalStrings(
            DWRITE_INFORMATIONAL_STRING_FULL_NAME, &pNames, &exists)) && exists) {
            fontInfo.localizedName = GetLocalizedStringSafe(pNames);
            SafeRelease(&pNames);
        }

        SafeRelease(&pFontFamily);
    }
}

void FontEnumerator::GetFontFaceInfo(IDWriteFontFace* pFontFace, FontInfo& fontInfo) {
    IDWriteFontFace3* pFontFace3 = nullptr;
    HRESULT hr = pFontFace->QueryInterface(__uuidof(IDWriteFontFace3), (void**)&pFontFace3);
    if (FAILED(hr)) return;

    // 使用智能指针确保资源释放
    auto fontFaceDeleter = [](IDWriteFontFace3* p) { if (p) p->Release(); };
    std::unique_ptr<IDWriteFontFace3, decltype(fontFaceDeleter)> fontFaceHolder(pFontFace3, fontFaceDeleter);

    // 获取字体文件路径
    GetFontFilePath(pFontFace3, fontInfo);

    // 获取字体元数据
    GetFontMetadata(pFontFace3, fontInfo);

    // 获取支持的字符集
    GetSupportedCharacters(pFontFace3, fontInfo);
}

void FontEnumerator::GetFontFilePath(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo) {
    UINT32 numFiles = 0;
    HRESULT hr = pFontFace3->GetFiles(&numFiles, nullptr);
    if (FAILED(hr) || numFiles == 0) return;

    IDWriteFontFile* pFontFile = nullptr;
    hr = pFontFace3->GetFiles(&numFiles, &pFontFile);
    if (FAILED(hr)) return;

    const void* referenceKey = nullptr;
    UINT32 referenceKeySize = 0;
    hr = pFontFile->GetReferenceKey(&referenceKey, &referenceKeySize);
    if (FAILED(hr)) {
        SafeRelease(&pFontFile);
        return;
    }

    IDWriteFontFileLoader* pFontFileLoader = nullptr;
    hr = pFontFile->GetLoader(&pFontFileLoader);
    if (FAILED(hr)) {
        SafeRelease(&pFontFile);
        return;
    }

    IDWriteLocalFontFileLoader* pLocalFileLoader = nullptr;
    hr = pFontFileLoader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), (void**)&pLocalFileLoader);
    if (SUCCEEDED(hr)) {
        UINT32 filePathLength = 0;
        hr = pLocalFileLoader->GetFilePathLengthFromKey(referenceKey, referenceKeySize, &filePathLength);
        if (SUCCEEDED(hr) && filePathLength > 0) {
            std::wstring filePath(filePathLength + 1, L'\0');
            hr = pLocalFileLoader->GetFilePathFromKey(referenceKey, referenceKeySize, &filePath[0], filePathLength + 1);
            if (SUCCEEDED(hr)) {
                filePath.resize(filePathLength);
                fontInfo.filePath = filePath;
            }
        }
        SafeRelease(&pLocalFileLoader);
    }

    SafeRelease(&pFontFileLoader);
    SafeRelease(&pFontFile);
}

void FontEnumerator::GetFontMetadata(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo) {
    // 设计师信息
    IDWriteLocalizedStrings* pStrings = nullptr;
    BOOL exists = FALSE;
    if (SUCCEEDED(pFontFace3->GetInformationalStrings(
        DWRITE_INFORMATIONAL_STRING_DESIGNER, &pStrings, &exists)) && exists) {
        fontInfo.designer = GetLocalizedStringSafe(pStrings);
        SafeRelease(&pStrings);
    }

    // 版权信息
    if (SUCCEEDED(pFontFace3->GetInformationalStrings(
        DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &pStrings, &exists)) && exists) {
        fontInfo.copyright = GetLocalizedStringSafe(pStrings);
        SafeRelease(&pStrings);
    }

    // 版本信息
    if (SUCCEEDED(pFontFace3->GetInformationalStrings(
        DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, &pStrings, &exists)) && exists) {
        fontInfo.version = GetLocalizedStringSafe(pStrings);
        SafeRelease(&pStrings);
    }

    // 商标信息
    if (SUCCEEDED(pFontFace3->GetInformationalStrings(
        DWRITE_INFORMATIONAL_STRING_TRADEMARK, &pStrings, &exists)) && exists) {
        fontInfo.trademark = GetLocalizedStringSafe(pStrings);
        SafeRelease(&pStrings);
    }
}void FontEnumerator::GetSupportedCharacters(IDWriteFontFace3* pFontFace3, FontInfo& fontInfo) {
    fontInfo.unicodeRanges.clear();

    if (!pFontFace3) {
        std::cerr << "错误: pFontFace3 是空指针" << std::endl;
        return;
    }

    // 第一次调用:获取所需范围数量
    UINT32 rangeCount = 0;
    HRESULT hr = pFontFace3->GetUnicodeRanges(0, nullptr, &rangeCount); //第一次调用不能获取返回值
    

    if (rangeCount == 0) {
        std::cout << "警告: 字体未声明任何Unicode范围" << std::endl;
        return;
    }

    // 分配足够大的缓冲区
    std::vector<DWRITE_UNICODE_RANGE> ranges(rangeCount);

    // 第二次调用:获取实际数据
    UINT32 actualRangeCount = 0;
    hr = pFontFace3->GetUnicodeRanges(rangeCount, ranges.data(), &actualRangeCount);
    if (FAILED(hr)) {
        _com_error err(hr);
        std::cerr << "获取Unicode范围数据失败: " << err.ErrorMessage()
            << " (实际需要大小: " << actualRangeCount
            << ", 分配大小: " << rangeCount << ")" << std::endl;
        return;
    }

    // 检查实际返回数量是否匹配
    if (actualRangeCount > rangeCount) {
        std::cerr << "警告: 实际范围数量(" << actualRangeCount
            << ")超过预期(" << rangeCount << ")" << std::endl;
        ranges.resize(actualRangeCount);
        hr = pFontFace3->GetUnicodeRanges(actualRangeCount, ranges.data(), &actualRangeCount);
        if (FAILED(hr)) return;
    }

    // 保存有效数据
    fontInfo.unicodeRanges.assign(ranges.begin(), ranges.begin() + actualRangeCount);
}
// 安全释放COM对象
template<class T> void SafeRelease(T** ppT) {
    if (*ppT) {
        (*ppT)->Release();
        *ppT = nullptr;
    }
}
相关推荐
cpsvps_net2 小时前
美国服务器环境下Windows容器工作负载智能弹性伸缩
windows
甄超锋2 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
cpsvps4 小时前
美国服务器环境下Windows容器工作负载基于指标的自动扩缩
windows
网硕互联的小客服7 小时前
Apache 如何支持SHTML(SSI)的配置方法
运维·服务器·网络·windows·php
etcix8 小时前
implement copy file content to clipboard on Windows
windows·stm32·单片机
许泽宇的技术分享8 小时前
Windows MCP.Net:基于.NET的Windows桌面自动化MCP服务器深度解析
windows·自动化·.net
非凡ghost9 小时前
AMS PhotoMaster:全方位提升你的照片编辑体验
windows·学习·信息可视化·软件需求
mortimer10 小时前
一次与“顽固”外部程序的艰难交锋:subprocess 调用exe踩坑实录
windows·python·ai编程
gameatp13 小时前
从 Windows 到 Linux 服务器的全自动部署教程(免密登录 + 压缩 + 上传 + 启动)
linux·服务器·windows
穷人小水滴13 小时前
在 windows 运行 flatpak 应用 (WSL)
linux·windows·ubuntu