Search code examples
macosfontscore-text

How do I retrieve attributes of an uninstalled font on OS X?


I’m trying to read attributes (font name, font format etc.) of an uninstalled font.

I have copied the Menlo.ttc file from /System/Library/Fonts/Menlo.ttc on my desktop and I have downloaded and installed the Caviar Dreams font.

I tried the following code:

#import <Foundation/Foundation.h>
#import <CoreText/CoreText.h>

static void printFontInfo(NSURL *fontURL)
{
    NSLog(@"%@", [fontURL path]);
    NSLog(@"    file size: %lld", [[[NSFileManager defaultManager] attributesOfItemAtPath:[fontURL path] error:NULL] fileSize]);

    NSDictionary *attributes = @{ (id)kCTFontURLAttribute: fontURL };
    CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attributes);
    CFNumberRef format = CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFormatAttribute);
    CFStringRef fontName = CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontNameAttribute);
    CFStringRef displayName = CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontDisplayNameAttribute);
    NSLog(@"    fontDescriptor: %p", fontDescriptor);
    NSLog(@"    format: %@", format);
    NSLog(@"    font name: %@", fontName);
    NSLog(@"    display name: %@", displayName);
}

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSURL *desktopURL = [fileManager URLForDirectory:NSDesktopDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:NULL];
        NSURL *downloadsURL = [fileManager URLForDirectory:NSDownloadsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:NULL];
        NSURL *fontsURL = [[fileManager URLForDirectory:NSLibraryDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:NULL] URLByAppendingPathComponent:@"Fonts"];

        NSURL *menloURL = [NSURL fileURLWithPath:@"/System/Library/Fonts/Menlo.ttc"];
        NSURL *copiedMenloURL = [desktopURL URLByAppendingPathComponent:@"Menlo.ttc"];
        NSURL *installedCaviarDreamsURL = [fontsURL URLByAppendingPathComponent:@"CaviarDreams.ttf"];
        NSURL *downloadedCaviarDreamsURL = [downloadsURL URLByAppendingPathComponent:@"caviar_dreams/CaviarDreams.ttf"];

        printFontInfo(menloURL);
        printFontInfo(copiedMenloURL);
        printFontInfo(installedCaviarDreamsURL);
        printFontInfo(downloadedCaviarDreamsURL);
    }
    return 0;
}

Running this code produces the following result:

/System/Library/Fonts/Menlo.ttc
    file size: 2144600
    fontDescriptor: 0x100111550
    format: 3
    font name: Menlo-Regular
    display name: Menlo Regular
/Users/0xced/Desktop/Menlo.ttc
    file size: 2144600
    fontDescriptor: 0x100117fa0
    format: (null)
    font name: (null)
    display name: (null)
/Users/0xced/Library/Fonts/CaviarDreams.ttf
    file size: 58864
    fontDescriptor: 0x100118f30
    format: 3
    font name: CaviarDreams
    display name: Caviar Dreams
/Users/0xced/Downloads/caviar_dreams/CaviarDreams.ttf
    file size: 58864
    fontDescriptor: 0x1001186c0
    format: (null)
    font name: (null)
    display name: (null)

We see that we can read attributes when the fonts are installed (either inside /System/Library/Fonts or ~/Library/Fonts) but that the CTFontDescriptorCopyAttribute function fails when the font is not in a system fonts directory.

Is there a way to read font attributes when the font is not installed?


Solution

  • You have to use CTFontManagerCreateFontDescriptorsFromURL(fontURL) instead of CTFontDescriptorCreateWithAttributes(@{ (id)kCTFontURLAttribute: fontURL }). The CTFontManagerCreateFontDescriptorsFromURL function returns an array of CTFontDescriptorRef objects.