mac 字体遍历demo

文章目录

逻辑字体类

cpp 复制代码
#ifndef LOGICAL_FONT_H
#define LOGICAL_FONT_H

#include <string>
#include <memory>
#include <CoreText/CoreText.h>
#include <CoreFoundation/CoreFoundation.h>

class LogicalFont {
public:
    LogicalFont() = default;
    ~LogicalFont() {
        if (character_set_) {
            CFRelease(character_set_);
        }
    }

    // Getters and setters for font names
    const std::string& en_family_name() const { return family_name_; }
    const std::string& en_face_name() const { return style_name_; }
    const std::string& en_postscript_name() const { return postscript_name_; }
    const std::string& localized_family_name() const { return localized_family_name_; }
    const std::string& localized_style_name() const { return localized_style_name_; }
    const std::string& localized_postscript_name() const { return localized_postscript_name_; }
    const std::string& full_name() const { return full_name_; }
    const std::string& font_path() const { return font_path_; }

    void set_family_name(const std::string& name) { family_name_ = name; }
    void set_style_name(const std::string& name) { style_name_ = name; }
    void set_postscript_name(const std::string& name) { postscript_name_ = name; }
    void set_localized_family_name(const std::string& name) { localized_family_name_ = name; }
    void set_localized_style_name(const std::string& name) { localized_style_name_ = name; }
    void set_localized_postscript_name(const std::string& name) { localized_postscript_name_ = name; }
    void set_full_name(const std::string& name) { full_name_ = name; }
    void set_font_path(const std::string& path) { font_path_ = path; }

    // Getters and setters for font metrics
    int32_t ascent() const { return ascent_; }
    int32_t descent() const { return descent_; }
    int32_t line_gap() const { return line_gap_; }
    int32_t cap_height() const { return cap_height_; }
    int32_t x_height() const { return x_height_; }
    int32_t underline_position() const { return underline_position_; }
    int32_t underline_thickness() const { return underline_thickness_; }
    int32_t strikethrough_position() const { return strikethrough_position_; }
    int32_t strikethrough_thickness() const { return strikethrough_thickness_; }
    int32_t slant_angle() const { return slant_angle_; }
    float weight() const { return weight_; }
    float width() const { return width_; }

    void set_ascent(int32_t value) { ascent_ = value; }
    void set_descent(int32_t value) { descent_ = value; }
    void set_line_gap(int32_t value) { line_gap_ = value; }
    void set_cap_height(int32_t value) { cap_height_ = value; }
    void set_x_height(int32_t value) { x_height_ = value; }
    void set_underline_position(int32_t value) { underline_position_ = value; }
    void set_underline_thickness(int32_t value) { underline_thickness_ = value; }
    void set_strikethrough_position(int32_t value) { strikethrough_position_ = value; }
    void set_strikethrough_thickness(int32_t value) { strikethrough_thickness_ = value; }
    void set_slant_angle(int32_t value) { slant_angle_ = value; }
    void set_weight(float value) { weight_ = value; }
    void set_width(float value) { width_ = value; }

    // Getters and setters for font style attributes
    bool bold() const { return bold_; }
    bool italic() const { return italic_; }

    void set_bold(bool value) { bold_ = value; }
    void set_italic(bool value) { italic_ = value; }

    // Character set handling
    CFCharacterSetRef character_set() const { return character_set_; }
    void set_character_set(CFCharacterSetRef charset) {
        if (character_set_) {
            CFRelease(character_set_);
        }
        // 添加显式类型转换
        character_set_ = (CFCharacterSetRef)CFRetain(charset);
    }

    // CTFontRef handling
    CTFontRef logical_font() const { return logical_font_; }
    void set_logical_font(CTFontRef font) { logical_font_ = font; }

private:
    // Font names
    std::string family_name_;               // English family name
    std::string style_name_;                // English style/face name
    std::string postscript_name_;           // English PostScript name
    std::string localized_family_name_;     // Localized family name
    std::string localized_style_name_;      // Localized style name
    std::string localized_postscript_name_; // Localized PostScript name
    std::string full_name_;                 // Full font name (family + style)
    std::string font_path_;                 // Path to font file

    // Font metrics
    int32_t ascent_ = 0;
    int32_t descent_ = 0;
    int32_t line_gap_ = 0;
    int32_t cap_height_ = 0;
    int32_t x_height_ = 0;
    int32_t underline_position_ = 0;
    int32_t underline_thickness_ = 0;
    int32_t strikethrough_position_ = 0;
    int32_t strikethrough_thickness_ = 0;
    int32_t slant_angle_ = 0;
    float weight_ = 0.0f;
    float width_ = 0.0f;

    // Font style attributes
    bool bold_ = false;
    bool italic_ = false;

    // Character set
    CFCharacterSetRef character_set_ = nullptr;

    // CoreText font reference (weak reference, not owned)
    CTFontRef logical_font_ = nullptr;
};

#endif // LOGICAL_FONT_H

头文件

cpp 复制代码
#pragma once
#include <memory>
#include <CoreText/CoreText.h>
#include <type_traits>
#include <CoreText/CoreText.h>
#include <CoreGraphics/CoreGraphics.h>
#include <iostream>
 
#include<memory>
#include <CoreText/CoreText.h>
 #include <iostream>
#include <fstream>
#include <map>
#include <string>
#include<unordered_set>
#include "LogicalFont.hpp"


namespace FontUtils {

    // CFString转std::string
    std::string CFStringToStdString(CFStringRef cfStr);

    // Unicode范围结构体
    struct UnicodeRange {
        uint32_t start;  // 范围起始码点
        uint32_t end;    // 范围结束码点
    };

    // CFURL转文件路径
    std::string CFURLToPath(CFURLRef url);

    // 字符串规范化(去空格/符号+转小写)
    std::string NormalizeString(std::string input);

} // namespace FontUtils

class FontManagerMac
{
public:
    FontManagerMac() {};
    ~FontManagerMac() {};

    void EnumerateSystemFonts();
 
private:
        // 处理所有字体家族
    void ProcessFontFamilies(CFArrayRef fontFamilies);
        // 处理单个字体家族
    void ProcessSingleFontFamily(CFStringRef familyName);
        // 处理字体描述符数组
    void ProcessFontDescriptors(CFArrayRef fontDescriptors, CFStringRef familyName);
        // 处理单个字体
    void ProcessSingleFont(CTFontDescriptorRef fontDescriptor, CFStringRef familyName, CFIndex index);
 
    
    void StoreFontInfo(const std::shared_ptr<LogicalFont>& log_font);
    bool GetFontInfo(std::shared_ptr<LogicalFont>& font, CTFontRef ctFont);
    bool GetExtendedFontMetrics(std::shared_ptr<LogicalFont> &font, CTFontRef ctf_font);
     
    std::vector<FontUtils::UnicodeRange> GetSupportedUnicodeRanges(CTFontRef font);
    


public: //为了便于演示这些数据,直接设置为公开的
        // 字体对象映射容器
    std::unordered_map<std::string, std::shared_ptr<LogicalFont>> postscript_to_font_;
    std::unordered_map<std::string, std::shared_ptr<LogicalFont>> local_postscript_to_font_;
    std::unordered_map<std::string, std::shared_ptr<LogicalFont>> full_to_font_;
    
    // 名称集合容器
    std::unordered_set<std::string> family_set_;
    std::unordered_set<std::string> postscript_set_;
    std::unordered_set<std::string> local_family_set_;
    std::unordered_set<std::string> local_postscript_set_;
    
    // 名称映射容器
    std::unordered_map<std::string, std::string> postscript_to_family_;
    std::unordered_map<std::string, std::string> en_to_local_family_;
    std::unordered_map<std::string, std::string> local_to_en_ps_;

    std::map<std::string, std::vector<FontUtils::UnicodeRange>> font_unicode_ranges_map_ ; 


        // 打印所有字体容器数据
    void PrintAllFontData() const {
        std::cout << "\n========== Font Container Data ==========\n";
        
        PrintFontMaps();
        PrintNameSets();
        PrintNameMappings();
        // PrintUnicodeRanges();
        
        std::cout << "========================================\n";
    }
private:
      // 打印字体对象映射
    void PrintFontMaps() const {
        std::cout << "\n[Font Object Mappings]\n";
        
        PrintMap("PostScript to Font", postscript_to_font_);
        PrintMap("Localized PostScript to Font", local_postscript_to_font_);
        PrintMap("Full Name to Font", full_to_font_);
    }

    // 打印名称集合
    void PrintNameSets() const {
        std::cout << "\n[Name Sets]\n";
        
        PrintSet("Family Names", family_set_);
        PrintSet("PostScript Names", postscript_set_);
        PrintSet("Localized Family Names", local_family_set_);
        PrintSet("Localized PostScript Names", local_postscript_set_);
    }

    // 打印名称映射
    void PrintNameMappings() const {
        std::cout << "\n[Name Mappings]\n";
        
        PrintStringMap("PostScript to Family", postscript_to_family_);
        PrintStringMap("English to Local Family", en_to_local_family_);
        PrintStringMap("Local to English PostScript", local_to_en_ps_);
    }

    // 打印Unicode范围
    void PrintUnicodeRanges() const {
        std::cout << "\n[Unicode Ranges by Font]\n";
        
        for (const auto& [fontName, ranges] : font_unicode_ranges_map_) {
            std::cout << "  " << fontName << ":\n";
            for (const auto& range : ranges) {
                std::cout << "    U+" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') 
                          << range.start << "-U+" << std::setw(4) << range.end << std::dec << "\n";
            }
        }
    }

    // 辅助函数:打印unordered_map<string, shared_ptr>
    template<typename T>
    void PrintMap(const std::string& title, const std::unordered_map<std::string, std::shared_ptr<T>>& map) const {
        std::cout << "  " << title << " (" << map.size() << " items):\n";
        for (const auto& [key, value] : map) {
            std::cout << "    " << std::setw(40) << std::left << key 
                      << " -> " << (value ? value->en_postscript_name() : "nullptr") << "\n";
        }
    }

    // 辅助函数:打印unordered_set<string>
    void PrintSet(const std::string& title, const std::unordered_set<std::string>& set) const {
        std::cout << "  " << title << " (" << set.size() << " items):\n    ";
        size_t count = 0;
        for (const auto& item : set) {
            std::cout << item;
            if (++count % 5 == 0 && count != set.size()) std::cout << "\n    ";
            else if (count != set.size()) std::cout << ", ";
        }
        std::cout << "\n";
    }

    // 辅助函数:打印unordered_map<string, string>
    void PrintStringMap(const std::string& title, const std::unordered_map<std::string, std::string>& map) const {
        std::cout << "  " << title << " (" << map.size() << " items):\n";
        for (const auto& [key, value] : map) {
            std::cout << "    " << std::setw(40) << std::left << key 
                      << " -> " << value << "\n";
        }
    }
};

实现文件

cpp 复制代码
#include "mac_font_traversal.h"
using std::shared_ptr;

namespace FontUtils {

	std::string CFStringToStdString(CFStringRef cfStr) {
		if (!cfStr) return "";

		CFIndex length = CFStringGetLength(cfStr);
		CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
		std::unique_ptr<char[]> buffer(new char[maxSize]);

		if (CFStringGetCString(cfStr, buffer.get(), maxSize, kCFStringEncodingUTF8)) {
			return std::string(buffer.get());
		}

		return "";
	}

    std::string CFURLToPath(CFURLRef url) {
		if (!url) {
			return {}; // 返回空字符串如果 URL 是空的
		}

		char path[PATH_MAX];
		if (!CFURLGetFileSystemRepresentation(url, true, (UInt8*)path, PATH_MAX)) {
			return {}; // 返回空字符串如果转换失败
		}

		return std::string(path); // 转换成功,返回路径字符串
	}


std::string NormalizeString(std::string input) {
		std::string result;
		result.reserve(input.size());
 
		for (const unsigned char ch : input) {
			if (ch != ' ' && ch != '-' && ch != '_' && ch != ',' && !std::isspace(ch)) {
				result += std::tolower(ch);
			}
		}

		return result;
	}



}


 
 

// 函数:获取字体支持的Unicode范围
// 参数:字体引用(CTFontRef)
// 返回值:该字体支持的Unicode范围集合(vector<UnicodeRange>)
std::vector<FontUtils::UnicodeRange> FontManagerMac::GetSupportedUnicodeRanges(CTFontRef font) {
    std::vector<FontUtils::UnicodeRange> tempRanges; // 临时存储范围集合
    
    if (!font) {  // 检查字体引用是否有效
        return tempRanges; // 无效则返回空集合
    }

    // 1. 获取字体支持的字符集
    CFCharacterSetRef charset = CTFontCopyCharacterSet(font); // 复制字体字符集
    // 创建字符集的位图表示
    CFDataRef bitmapData = CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault, charset);
    const UInt8 *bitmap = CFDataGetBytePtr(bitmapData); // 获取位图数据指针
    CFIndex length = CFDataGetLength(bitmapData);      // 获取位图数据长度

    bool inRange = false;   // 标记是否处于连续范围内
    uint32_t start = 0;     // 当前范围的起始码点
    uint32_t maxChar = 0;   // 当前范围的结束码点

    // 2. 遍历位图,检测并合并连续范围
    for (uint32_t byteIndex = 0; byteIndex < length; byteIndex++) {
        UInt8 byte = bitmap[byteIndex]; // 获取当前字节
        
        if (byte == 0) {  // 如果字节为0,表示没有支持的字符
            if (inRange) { // 如果之前处于范围内,则结束当前范围
                tempRanges.push_back({start, (byteIndex << 3) - 1});
                inRange = false;
            }
            continue; // 跳过后续处理
        }

        // 检查字节中的每一位(共8位)
        for (uint32_t bit = 0; bit < 8; bit++) {
            uint32_t currentChar = (byteIndex << 3) + bit; // 计算当前字符码点
            bool isSupported = (byte & (1 << bit)) != 0;   // 检查当前位是否被支持

            if (isSupported) {  // 如果字符被支持
                if (!inRange) { // 如果不在范围内,则开始新范围
                    start = currentChar;
                    inRange = true;
                }
                maxChar = currentChar; // 更新范围结束码点
            } else if (inRange) { // 如果字符不被支持但之前处于范围内
                tempRanges.push_back({start, currentChar - 1}); // 结束当前范围
                inRange = false;
            }
        }
    }

    // 处理最后一个范围(如果遍历结束时仍处于范围内)
    if (inRange) {
        tempRanges.push_back({start, maxChar});
    }

    // 3. 压缩范围(合并相邻或重叠的范围)
    if (!tempRanges.empty()) {
        size_t compressedCount = 0; // 压缩后的范围计数
        
        // 遍历所有范围
        for (size_t i = 1; i < tempRanges.size(); i++) {
            // 如果当前范围与前一个范围相邻或重叠
            if (tempRanges[i].start <= tempRanges[compressedCount].end + 1) {
                // 合并范围(取最大的结束码点)
                if (tempRanges[i].end > tempRanges[compressedCount].end) {
                    tempRanges[compressedCount].end = tempRanges[i].end;
                }
            } else {
                // 不重叠则保留当前范围
                compressedCount++;
                tempRanges[compressedCount] = tempRanges[i];
            }
        }
        // 调整向量大小为压缩后的数量
        tempRanges.resize(compressedCount + 1);
    }

    // 释放资源
    CFRelease(bitmapData);
    CFRelease(charset);
    
    return tempRanges; // 返回最终的范围集合
}
void FontManagerMac::StoreFontInfo(const std::shared_ptr<LogicalFont>& font) {
    
    
        // 规范化名称
        const auto norm_face_name = FontUtils::NormalizeString(font->en_face_name());
        const auto norm_family_name = FontUtils::NormalizeString(font->en_family_name());
        const auto norm_ps_name = FontUtils::NormalizeString(font->en_postscript_name());
        const auto norm_local_ps_name = FontUtils::NormalizeString(font->localized_postscript_name());
        const auto norm_local_family_name = FontUtils::NormalizeString(font->localized_family_name());
        const auto norm_full_name = FontUtils::NormalizeString(font->full_name());
    
        // 字体对象映射
        postscript_to_font_.emplace(norm_ps_name, font);
        local_postscript_to_font_.emplace(norm_local_ps_name, font);
        full_to_font_.emplace(norm_full_name, font);
    
        // 名称集合
        family_set_.insert(norm_family_name);
        postscript_set_.insert(norm_ps_name);

        // 家族与Postscript名映射
        //family_to_postscript_[norm_family_name].insert(norm_ps_name);
        postscript_to_family_.emplace(norm_ps_name, norm_family_name);

        // 本地化名称集合
        local_family_set_.insert(font->localized_family_name());
        local_postscript_set_.insert(font->localized_postscript_name());

        // 本地化与标准名称映射
        en_to_local_family_.emplace(norm_family_name, norm_local_family_name);
        local_to_en_ps_.emplace(norm_local_ps_name, norm_ps_name);
        //处理对应的unicode 支持范围
        font_unicode_ranges_map_.try_emplace(norm_family_name,GetSupportedUnicodeRanges(font->logical_font()));
    
}
    // 枚举系统字体
    void FontManagerMac::EnumerateSystemFonts() {
        // 获取系统所有可用字体家族名称数组
        CFArrayRef fontFamilies = CTFontManagerCopyAvailableFontFamilyNames();
        
        // 检查是否成功获取字体家族列表
        if (!fontFamilies) {
            std::cerr << "Error: Unable to get system font family list" << std::endl;
            return;
        }
        
        // 处理所有字体家族
        ProcessFontFamilies(fontFamilies);
        
        // 释放字体家族数组内存
        CFRelease(fontFamilies);
    }

    // 处理所有字体家族
    void FontManagerMac::ProcessFontFamilies(CFArrayRef fontFamilies) {
        // 获取字体家族数量
        CFIndex familyCount = CFArrayGetCount(fontFamilies);
        
        // 遍历每个字体家族
        for (CFIndex i = 0; i < familyCount; ++i) {
            // 获取当前索引的字体家族名称
            CFStringRef familyName = (CFStringRef)CFArrayGetValueAtIndex(fontFamilies, i);
            
            // 检查是否成功获取家族名称
            if (!familyName) {
                std::cerr << "Warning: Failed to get font family name at index " << i << std::endl;
                continue;
            }
            
            // 处理单个字体家族
            ProcessSingleFontFamily(familyName);
        }
    }

    // 处理单个字体家族
    void FontManagerMac::ProcessSingleFontFamily(CFStringRef familyName) {
        // 创建字体描述符(指定家族名称和默认大小0)
        CTFontDescriptorRef familyDescriptor = CTFontDescriptorCreateWithNameAndSize(familyName, 0);
        
        // 检查是否成功创建描述符
        if (!familyDescriptor) {
            std::cerr << "Warning: Failed to create descriptor for family "
                      << FontUtils::CFStringToStdString(familyName) << std::endl;
            return;
        }
        
        // 获取匹配该家族的所有字体描述符
        CFArrayRef fontDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(familyDescriptor, NULL);
        
        // 释放家族描述符内存
        CFRelease(familyDescriptor);
        
        // 检查是否获取到字体描述符
        if (!fontDescriptors) {
            std::cerr << "Warning: No fonts found for family "
                      << FontUtils::CFStringToStdString(familyName) << std::endl;
            return;
        }
        
        // 处理该家族下的所有字体描述符
        ProcessFontDescriptors(fontDescriptors, familyName);
        
        // 释放字体描述符数组内存
        CFRelease(fontDescriptors);
    }

    // 处理字体描述符数组
    void FontManagerMac::ProcessFontDescriptors(CFArrayRef fontDescriptors, CFStringRef familyName) {
        // 获取字体描述符数量
        CFIndex fontCount = CFArrayGetCount(fontDescriptors);
        
        // 遍历每个字体描述符
        for (CFIndex j = 0; j < fontCount; ++j) {
            // 获取当前索引的字体描述符
            CTFontDescriptorRef fontDescriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fontDescriptors, j);
            
            // 处理单个字体
            ProcessSingleFont(fontDescriptor, familyName, j);
        }
    }

    // 处理单个字体
    void FontManagerMac::ProcessSingleFont(CTFontDescriptorRef fontDescriptor, CFStringRef familyName, CFIndex index) {
        // 根据描述符创建字体对象
        CTFontRef font = CTFontCreateWithFontDescriptor(fontDescriptor, 0.0, NULL);
        
        // 检查是否成功创建字体
        if (!font) {
            std::cerr << "Warning: Failed to create font for descriptor " << index
                      << " in family " << FontUtils::CFStringToStdString(familyName) << std::endl;
            return;
        }
        
        // 创建逻辑字体对象
        auto log_font = std::make_shared<LogicalFont>();
        
        // 设置字体属性并存储有效字体
        if (GetFontInfo(log_font, font)) {
            StoreFontInfo(log_font);
        }
        
        // 释放字体对象内存
        CFRelease(font);
    }


 

bool FontManagerMac::GetExtendedFontMetrics(std::shared_ptr<LogicalFont>& font, CTFontRef ctf_font) {
    if (!ctf_font || !font) return false;

    // 获取基本度量信息
    font->set_ascent(static_cast<int32_t>(CTFontGetAscent(ctf_font)));
    font->set_descent(static_cast<int32_t>(CTFontGetDescent(ctf_font)));
    font->set_line_gap(static_cast<int32_t>(CTFontGetLeading(ctf_font)));
    font->set_cap_height(static_cast<int32_t>(CTFontGetCapHeight(ctf_font)));
    font->set_x_height(static_cast<int32_t>(CTFontGetXHeight(ctf_font)));

    // 下划线信息
    font->set_underline_position(static_cast<int32_t>(CTFontGetUnderlinePosition(ctf_font)));
    font->set_underline_thickness(static_cast<int32_t>(CTFontGetUnderlineThickness(ctf_font)));

    // 删除线信息(估算)
    font->set_strikethrough_position(static_cast<int32_t>(font->strikethrough_position() * 0.5f));
    font->set_strikethrough_thickness(font->underline_thickness());

    // 斜体角度
    if (&CTFontGetSlantAngle != NULL) {
        font->set_slant_angle(static_cast<int32_t>(CTFontGetSlantAngle(ctf_font)));
    }

    // 字重
    CGFloat fontWeight = 0.0;
    CFDictionaryRef fontTraits = CTFontCopyTraits(ctf_font);
    if (fontTraits) {
        CFNumberRef weightTrait = (CFNumberRef)CFDictionaryGetValue(fontTraits, kCTFontWeightTrait);
        if (weightTrait) {
            CFNumberGetValue(weightTrait, kCFNumberCGFloatType, &fontWeight);
            fontWeight = (fontWeight - 0.4) / 0.6; // 标准化
        }
        CFRelease(fontTraits);
    }
    font->set_weight(fontWeight);

    // 字体宽度
    CGGlyph glyph;
    UniChar testChar = 'x';
    if (CTFontGetGlyphsForCharacters(ctf_font, &testChar, &glyph, 1)) {
        CGSize advance;
        CTFontGetAdvancesForGlyphs(ctf_font, kCTFontOrientationHorizontal, &glyph, &advance, 1);
        font->set_width(advance.width);
    }
    
    return true;
}
// 获取字体信息并填充到LogicalFont对象中
bool FontManagerMac::GetFontInfo(std::shared_ptr<LogicalFont>& font, CTFontRef ctf_font) {
    if (!font || !ctf_font) return false;
    
    CTFontDescriptorRef descriptor = CTFontCopyFontDescriptor(ctf_font);
    if (!descriptor) return false;

    // 一次性获取所有基础属性
    CFStringRef family = nullptr;
    CFStringRef styleName = nullptr;
        // 获取 family 和 styleName
if ((family = static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute)))) {
            font->set_family_name(FontUtils::CFStringToStdString(family));
        }

if ((styleName = static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute)))) {
            font->set_style_name(FontUtils::CFStringToStdString(styleName));
        }

    // 设置全名(需要family和styleName)
    if (family && styleName) {
        font->set_full_name(
            FontUtils::CFStringToStdString(family) + " " +
            FontUtils::CFStringToStdString(styleName)
        );
    }

    // 获取本地化名称
    
        if (CFStringRef localizedFamily = CTFontCopyLocalizedName(ctf_font, kCTFontFamilyNameKey, nullptr)) {
            font->set_localized_family_name(FontUtils::CFStringToStdString(localizedFamily));
            CFRelease(localizedFamily);
        }

        if (styleName) { // 本地化样式名需要styleName
            if (CFStringRef localizedStyle = CTFontCopyLocalizedName(ctf_font, kCTFontStyleNameKey, nullptr)) {
                font->set_localized_style_name(FontUtils::CFStringToStdString(localizedStyle));
                CFRelease(localizedStyle);
            }
        }
    

    // 获取PostScript相关名称(独立操作)
    if (CFStringRef psName = CTFontCopyPostScriptName(ctf_font)) {
        font->set_postscript_name(FontUtils::CFStringToStdString(psName));
        CFRelease(psName);

        if (CFStringRef localizedPsName = CTFontCopyLocalizedName(ctf_font, kCTFontPostScriptNameKey, nullptr)) {
            font->set_localized_postscript_name(FontUtils::CFStringToStdString(localizedPsName));
            CFRelease(localizedPsName);
        }
    }

    // 获取字符集
    if (CFCharacterSetRef fontChars = CTFontCopyCharacterSet(ctf_font)) {
        font->set_character_set(fontChars);
        CFRelease(fontChars);
    }

    // 获取字体路径
    if (CFURLRef fontURL = static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute))) {
        font->set_font_path(FontUtils::CFURLToPath(fontURL));
        CFRelease(fontURL);
    }

    // 释放基础属性
    if (family) CFRelease(family);
    if (styleName) CFRelease(styleName);

    // 获取扩展属性
 
    GetExtendedFontMetrics(font, ctf_font);
    font->set_logical_font(ctf_font);
    
    CFRelease(descriptor);
    return true;
}

使用文件主程序

cpp 复制代码
#include "mac_font_traversal.h"

int main()
{
    FontManagerMac  font_manager;
    font_manager.EnumerateSystemFonts();
    font_manager.PrintAllFontData();
}

CMakeLists文件

cpp 复制代码
cmake_minimum_required(VERSION 3.15)
project(FontManagerMac)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)

# 查找macOS系统框架
find_library(COREFOUNDATION CoreFoundation REQUIRED)
find_library(CORETEXT CoreText REQUIRED)

# 添加库目标
add_executable(FontManagerMac
    ${CMAKE_CURRENT_SOURCE_DIR}/LogicalFont.hpp
    ${CMAKE_CURRENT_SOURCE_DIR}/mac_font_traversal.h
    ${CMAKE_CURRENT_SOURCE_DIR}/mac_font_traversal.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)

# 链接系统框架
target_link_libraries(FontManagerMac PRIVATE
    ${COREFOUNDATION}
    ${CORETEXT}
)
# 找到并链接 CoreGraphics 和 ImageIO 框架
if(APPLE)
    find_library(COREGRAPHICS_FRAMEWORK CoreGraphics)
    find_library(IMAGEIO_FRAMEWORK ImageIO)
    target_link_libraries(FontManagerMac  PRIVATE ${COREGRAPHICS_FRAMEWORK} ${IMAGEIO_FRAMEWORK})
endif()

# 包含当前目录
target_include_directories(FontManagerMac PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

# 针对Xcode额外设置
if(CMAKE_GENERATOR STREQUAL "Xcode")
    set_target_properties(FontManagerMac PROPERTIES
        XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES"
        XCODE_ATTRIBUTE_GCC_INPUT_FILETYPE "sourcecode.cpp.utf-8"
    )
endif()

脚本文件

bash 复制代码
#!/bin/bash

# Set root directory
root_dir=$(pwd)

# Function to perform the build
build() {
    local arch="$1"
    local build_type="$2"

    # Define directories
    build_dir=${root_dir}/build/mainmodule_build/MACOSX/${arch}
    install_dir=${root_dir}/install

    echo "Build dir: ${build_dir}"

    # Remove existing build dir to ensure a clean build
    if [ -e $build_dir ]; then
        rm -rf $build_dir
    fi

    # CMake command with common parameters
    cmake \
        -DBUILD_SHARED_LIBS:BOOL=TRUE \
        -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE \
        -DCMAKE_BUILD_TYPE:STRING=${build_type} \
        -DCMAKE_INSTALL_PREFIX=${install_dir} \
        -DCMAKE_OSX_ARCHITECTURES=${arch} \
        -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
        -DSYSTEM:STRING=Darwin \
        -DAFS_TARGET_PLATFORM=mac \
        -DAFS_BUILD_MODE:STRING=build \
        -G "Xcode" \
        -S ${root_dir} \
        -B ${build_dir}

    # Build and install
    cmake --build ${build_dir} \
        --config ${build_type} \
        -j 14 \
        --
}

# Call build function for Debug configurations only
build x86_64 Debug
# build arm64 Debug




# # 定义输出路径
# output_path="${root_dir}/install/bin"
# debug_libs_dir="${output_path}/Debug"

# # 确保Debug目录存在
# mkdir -p "${debug_libs_dir}"

# # 检查要合并的库文件是否存在
# x86_lib="${output_path}/x86_64/Debug/PDFCore.dylib"
# arm_lib="${output_path}/arm64/Debug/PDFCore.dylib"

# if [[ ! -f "${x86_lib}" || ! -f "${arm_lib}" ]]; then
#     echo "错误:找不到要合并的库文件"
#     echo "x86_64 库路径: ${x86_lib} - $(test -f "${x86_lib}" && echo "存在" || echo "不存在")"
#     echo "arm64 库路径: ${arm_lib} - $(test -f "${arm_lib}" && echo "存在" || echo "不存在")"
#     exit 1
# fi

# # 合并Debug版本库
# echo "正在合并Debug库..."
# lipo -create \
#   "${x86_lib}" \
#   "${arm_lib}" \
#   -output "${debug_libs_dir}/PDFCore.dylib"

# # 验证合并后的库
# if [[ -f "${debug_libs_dir}/PDFCore.dylib" ]]; then
#     echo "验证合并后的库架构:"
#     lipo -info "${debug_libs_dir}/PDFCore.dylib"
#     echo "库合并成功完成。"
# else
#     echo "错误:合并后的库文件未生成"
#     exit 1
# fi