10

I hear that fontconfig is the best option for getting fonts in linux. Unfortunately, I've been looking through their developer documentation and I have absolutely no clue what I'm doing. It would appear there is no simple function to get a list of system fonts. I have to perform a pattern search instead... right?

In short, what is the best way to get a list of true-type fonts (their family, face, and directory) with fontconfig? Of course, if there's something better than fontconfig, I'm certainly open to other solutions.

Azmisov
  • 6,493
  • 7
  • 53
  • 70

2 Answers2

15

I had a similar question, and found this post (the fontconfig documentation is a little difficult to get through). MindaugasJ's response was useful, but watch out for the extra lines calling things like FcPatternPrint() or printing out the results of FcNameUnparse(). In addition, you need to add a FC_FILE argument to the list of arguments passed to FcObjectSetBuild. Something like this:

FcConfig* config = FcInitLoadConfigAndFonts();
FcPattern* pat = FcPatternCreate();
FcObjectSet* os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, (char *) 0);
FcFontSet* fs = FcFontList(config, pat, os);

printf("Total matching fonts: %d\n", fs->nfont);
for (int i=0; fs && i < fs->nfont; ++i) {
   FcPattern* font = fs->fonts[i];
   FcChar8 *file, *style, *family;
   if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch &&
       FcPatternGetString(font, FC_FAMILY, 0, &family) == FcResultMatch &&
       FcPatternGetString(font, FC_STYLE, 0, &style) == FcResultMatch)
   {
      printf("Filename: %s (family %s, style %s)\n", file, family, style);
   }
}
if (fs) FcFontSetDestroy(fs);

I had a slightly different problem to solve in that I needed to find the font file to pass to freetype's FC_New_Face() function given some font "name". This code is able to use fontconfig to find the best file to match a name:

FcConfig* config = FcInitLoadConfigAndFonts();

// configure the search pattern, 
// assume "name" is a std::string with the desired font name in it
FcPattern* pat = FcNameParse((const FcChar8*)(name.c_str()));
FcConfigSubstitute(config, pat, FcMatchPattern);
FcDefaultSubstitute(pat);

// find the font
FcResult res;
FcPattern* font = FcFontMatch(config, pat, &res);
if (font)
{
   FcChar8* file = NULL;
   if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch)
   {
      // save the file to another std::string
      fontFile = (char*)file;
   }
   FcPatternDestroy(font);
}

FcPatternDestroy(pat);
user877329
  • 6,717
  • 8
  • 46
  • 88
Scott Minster
  • 422
  • 5
  • 9
  • 1
    There is typo in your code: FcChar8* file, style, family; You forgot to add * for style and family. Segfaults. – Mislav Blažević May 12 '14 at 13:25
  • Thank you both for your code guys, but when I ran this I got run-time assertion. output: "Microsoft Visual Studio C Runtime Library has detected a fatal error in test-fontconfig.exe." – codekiddy Feb 15 '15 at 02:11
  • 1
    @codekiddy replace the FcFontMatch line by: FcResult result = FcResultNoMatch; FcPattern* font = FcFontMatch(config, pat, &result); – Folkert van Heusden Jun 16 '15 at 20:15
  • typo: `FC_New_Face`, you probebly meant `FT_New_Face` – Kuldeep Dhaka Dec 29 '15 at 01:22
  • 2
    Your second Code example is illegal, as it passes a NULL Pointer in `FcFontMatch(config, pat, NULL)`, which will be dereferend and written to. Assertions are made in the debug version of fontconfig, but not in the release builds. Please address this issue! https://cgit.freedesktop.org/fontconfig/tree/src/fcmatch.c#n779 – Matze Sep 27 '16 at 16:11
  • See the comment from @FolkertvanHeusden – Matze Sep 27 '16 at 16:13
7

This is not exactly what you are asking for, but it will give you the list of fonts available.

#include <fontconfig.h>

FcPattern *pat;
FcFontSet *fs;
FcObjectSet *os;
FcChar8 *s, *file;
FcConfig *config;
FcBool result;
int i;

result = FcInit();
config = FcConfigGetCurrent();
FcConfigSetRescanInterval(config, 0);

// show the fonts (debugging)
pat = FcPatternCreate();
os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_LANG, (char *) 0);
fs = FcFontList(config, pat, os);
printf("Total fonts: %d", fs->nfont);
for (i=0; fs && i < fs->nfont; i++) {
    FcPattern *font = fs->fonts[i];//FcFontSetFont(fs, i);
    FcPatternPrint(font);
    s = FcNameUnparse(font);
    if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
        printf("Filename: %s", file);
    }
    printf("Font: %s", s);
    free(s);
}
if (fs) FcFontSetDestroy(fs);
Community
  • 1
  • 1
MindaugasJ
  • 93
  • 1
  • 6