使用Linux Fontconfig匹配字体规格提取字体列表遇问题求助
问题
我希望通过Fontconfig匹配指定字体规格来提取字体列表。编写的测试代码可以选出单个“最佳匹配”字体,但尝试列出备选字体时结果为空;若传入空模式则会列出系统所有字体,说明列表逻辑本身正常。
测试代码如下:
#include <stdio.h> #include <stdlib.h> #include <fontconfig/fontconfig.h> int main(){ FcConfig* config=NULL; FcPattern* pat=NULL; FcPattern* font=NULL; FcObjectSet* os=NULL; FcFontSet* fs=NULL; FcChar8* file=NULL; char* fontFile=NULL; FcResult result; int i; FcInit(); config = FcInitLoadConfigAndFonts(); pat = FcNameParse((const FcChar8*)"Mono"); //pat=FcPatternCreate(); FcConfigSubstitute(config, pat, FcMatchPattern); FcDefaultSubstitute(pat); //os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, (char *) 0); os = FcObjectSetBuild (FC_FAMILY, (char *) 0); fs = FcFontList(config, pat, os); printf("nfonts %d\n", fs->nfont); for (i=0; i<fs->nfont; i++){ font=fs->fonts[i]; FcPatternGetString(font, FC_FILE, 0, &file); printf("font# %d %s\n", i, (char*)file); }; // font = FcFontMatch(config, pat, &result); // // if (font){ // file = NULL; // // if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch){ // fontFile = (char*)file; // printf("%s\n",fontFile); // }; // }; FcFontSetDestroy(fs); FcObjectSetDestroy(os); //FcPatternDestroy(font); FcPatternDestroy(pat); FcConfigDestroy(config); FcFini(); return 0; }
原因与解决方法
核心问题
- 替换模式错误:
FcConfigSubstitute使用了FcMatchPattern参数,该参数是为单一最佳字体匹配设计的,会对模式进行严格调整,过滤掉所有非最优匹配的字体,导致FcFontList返回空列表。 - 属性请求缺失:
FcObjectSetBuild只请求了FC_FAMILY属性,但后续代码尝试获取FC_FILE,由于未请求该属性,FcPatternGetString会失败,即使有匹配字体也无法正确输出路径。
修复步骤
- 将
FcConfigSubstitute的第三个参数改为FcMatchFonts,该参数用于批量字体匹配,保留所有符合规格的备选字体。 - 在
FcObjectSetBuild中加入FC_FILE属性,确保能获取到字体文件路径。
修改后的关键代码片段
// 改用FcMatchFonts适配批量列表匹配 FcConfigSubstitute(config, pat, FcMatchFonts); FcDefaultSubstitute(pat); // 加入FC_FILE属性,保证能获取字体文件路径 os = FcObjectSetBuild(FC_FAMILY, FC_FILE, (char *) 0);
完整修复代码
#include <stdio.h> #include <stdlib.h> #include <fontconfig/fontconfig.h> int main(){ FcConfig* config=NULL; FcPattern* pat=NULL; FcPattern* font=NULL; FcObjectSet* os=NULL; FcFontSet* fs=NULL; FcChar8* file=NULL; char* fontFile=NULL; FcResult result; int i; FcInit(); config = FcInitLoadConfigAndFonts(); pat = FcNameParse((const FcChar8*)"Mono"); //pat=FcPatternCreate(); // 替换为FcMatchFonts,用于列表匹配 FcConfigSubstitute(config, pat, FcMatchFonts); FcDefaultSubstitute(pat); // 加入FC_FILE属性,确保能获取字体文件路径 os = FcObjectSetBuild(FC_FAMILY, FC_FILE, (char *) 0); fs = FcFontList(config, pat, os); printf("nfonts %d\n", fs->nfont); for (i=0; i<fs->nfont; i++){ font=fs->fonts[i]; if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { printf("font# %d %s\n", i, (char*)file); } }; FcFontSetDestroy(fs); FcObjectSetDestroy(os); FcPatternDestroy(pat); FcConfigDestroy(config); FcFini(); return 0; }
内容的提问来源于stack exchange,提问作者Marta
相关产品推荐
相关产品推荐

