Determining the Path to a Font file

Actually you need to pass “~/Library/Fonts/” to the nsopenpanel for it to open in the user’s font folder. The tilde means the current logged in user’s home folder path on every machines, no distinction whatsoever. The version you posted was the path to the local font folder on the sartup disk. :slight_smile:

It’s strange that we can’t get access to the font’s path. I’ll check this when time permits and post back any result.

Good luck with your project!

Browser: Safari 6533.18.5
Operating System: Mac OS X (10.6)

This is why I asked. On my system, the font folder in my home folder path is empty. All my fonts are in the Fonts folder in the Library folder of the start up disk. Like I said, I don’t know anything about font management. They just magically show up when I want to change them :). But it seems that the location can vary, perhaps depending on how they were installed? Regardless, it seems like it would be useful to have a way of finding the location of the Font folder. Interestingly, if I use “fonts folder” in applescript, it points to Fonts folder in Library in the system folder.

Yeah, well there is so many apps and tools that can play in the fonts folders that it is hard to make sense of it.

Yes in AS you can use fonts folder but if you use either “of system domain” or “of locale domain” or “of user domain” (I could be off on the exact spelling, memory…) then you can specify which one you want. Check in the AppleScript editor, within the library window, the standard additions I think, it will have more details.

Browser: Safari 6533.18.5
Operating System: Mac OS X (10.6)

Hi,

in Snow Leopard you can get the path of a NSFont with CTFontDescriptor (a part of CoreText > ApplicationServices.framework)


- (NSString)pathToFont:(NSFont *)font
{
	CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize ((CFStringRef)[font fontName], [font pointSize]);
	CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute);
	NSString *fontPath = [NSString stringWithString:[(NSURL *)url path]];
	CFRelease(fontRef);
	CFRelease(url);
	return fontPath;
}

The problem is you can’t use CoreFoundation code in ASOC.
But you could create a custom Cocoa class and call the method from there

I think this needs to be (NSString *)pathToFont:(NSFont *)font

With that change, StefanK’s method worked for me with this call to it:

set myPath to objC’s pathToFont_(current application’s NSFont’s fontWithName_size_(“Times-Roman”, 12))

objC is a property connected to the blue cube that is of the class GetPath (the name of the .h and .m files where I put Stefan’s objective-C code).

Ric

Of course :slight_smile:

FWIW, I think stuff like this is a good reason to consider having a base Objective-C class in your projects that your app delegate inherits from. You can then quickly add methods like this and call them directly, without having to add/instantiate/add property.

Stefan: Is there some special reason you put “NSString stringWithString:” in there?

Yeah, I agree – I sometimes forget about that option. Another fix that makes the method simpler, is to pass the font name and size instead of the font object – since you have to call current application’s NSFont’s fontWithName_size_ and pass it that information anyway and then the objective-C method just gets those values back from the font object (of course, if you already have the font object, then Stefan’s way would be easier). So, this is the code I have now:

script FontPathAppDelegate
	property parent : class "GetPath"
	
	on applicationWillFinishLaunching_(aNotification)
		set myPath to pathToFontNamed_size_("Times-Roman", 12)
		log myPath
	end applicationWillFinishLaunching_
	
end script

And the GetPath.m is:

@implementation GetPath

    - (NSString *)pathToFontNamed:(NSFont *)fontName size:(CGFloat)fontSize
    {
        CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize ((CFStringRef)fontName, fontSize);
        CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute);
        NSString *fontPath = [(NSURL *)url path];
        CFRelease(fontRef);
        CFRelease(url);
        return fontPath;
    }
@end

Ric

I think you meant NSString rather than NSFont…

Oops! Yeah, that’s what I meant to do (but I forgot to change it from stefan’s method, and it worked anyway).

Ric

I want to make sure to get a retained string before releasing the URL object

I’m lost. Are you writing this with GC in mind?

I could understand if you were returning url itself, but not its path…

No, I’m an old-fashioned memory management guy :wink:

Probably it’s overcautious and not needed,
but my intention is, if the derived path depends on the url object,
it’s safer to create a new string object before releasing the url object.

Well as I read things, we still need to manage memory at the CF level, albeit a bit differently.

Thanks. So if instead I did something like:

NSString *fontPath = NSMakeCollectable(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle))

I assume I’d be fine.

Actually you should write


NSString *fontPath = [NSMakeCollectable(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle)) autorelease];

because of the leak of CFURLCopyFileSystemPath.

I just tested this


NSString *fontPath = [(NSURL *)url path];

and it worked perfectly

Uhh … you guys lost me about 10 posts back when you started talking about custom classes :). Would the “Adding Objective-C Code” section in Shane’s book be a good place to start the deciphering process? I’ve glanced at it but I haven’t really gone over it very thoroughly since for some reason when I see the “.h’s” and “.m’s”, my brain seems to go into a shut down mode :).

It would certainly help.

To actually make a class, go to File → New File, and choose Objective-C class; give it a name, say MyNewClass. You will get two new files. In the .m file, paste the method code from Stefan or Ric between the @implementation and @end statements, then save. Got to the .h file and paste in just the signature of the method – up to the first { – before the @end line but outside the { and }. Instead of ending it with a {, end it with a semicolon, like this:

@interface MyNewClass : NSObject {
}

  • (NSString *)pathToFontNamed:(NSString *)fontName size:(CGFloat)fontSize;

@end

Save, and you’re set. You can either instantiate it (see the chapter Instantiating Script Objects), or you can just change the parent property of your script to the new class, and inherit the method.

Thanks. I’ll give it a try.

Greetings, It’s been a long time!

I need some help please. I’ve been using this class in a project I started 10 years ago and it’s been working fine, but now won’t compile. Below is the code as it stands now. I know there have been a lot of changes over the years, that I’m not up to date on, so was hoping a kind soul would be able to save me :). Thanks so much!

[format]@implementation MyPathToFontClass

  • (NSString *)pathToFontNamed:(NSFont *)fontName size:(CGFloat)fontSize
    {
    CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize ((const struct __CFString *)fontName, fontSize);
    CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute);
    NSString *fontPath = [(__bridge NSURL *)url path];
    //CFRelease(fontRef);
    //CFRelease(url);
    return fontPath;
    }
    @end[/format]

I’m getting the following issues:

[format]Unknown type name ‘CTFontDescriptorRef’; did you mean ‘CFFileDescriptorRef’?
Implicit declaration of function ‘CTFontDescriptorCreateWithNameAndSize’ is invalid in C99
Implicit declaration of function ‘CTFontDescriptorCopyAttribute’ is invalid in C99
Use of undeclared identifier ‘kCTFontURLAttribute’

  • (NSString *)pathToFontNamed:(NSFont *)fontName size:(CGFloat)fontSize > Expected a type
    Cast of Objective-C pointer type ‘id’ to C pointer type ‘const struct __CFString *’ requires a bridged cast
    Use __bridge to convert directly (no change in ownership)
    Use CFBridgingRetain call to make an ARC object available as a +1 ‘const struct __CFString *’
    Incompatible integer to pointer conversion initializing ‘CFFileDescriptorRef’ (aka ‘struct __CFFileDescriptor *’) with an expression of type ‘int’[/format]

@mac.jedi

The first line of the error message tells you that the compiler does not understand the ‘CTFontDescriptorRef’ class type.

So I suspect that you have upgraded to a newer operating system version, from the one used when creating your original code, and the ‘CTFontDescriptorRef’ class type is no longer supported on the newer OS version.

It’s important to quote your OS version when posting code on this forum, as a lot has changed to the newer “Big Sur” & “Monterey” operating system versions.

This works for me on “High Sierra”, but I have not checked it on my “Mojave” or “Catalina” partitions.


- (NSString *)filePathOfFont:(NSFont *)font {
	CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize ((CFStringRef)[font fontName], [font pointSize]);
	CFURLRef fontURL = (CFURLRef)CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute);
	NSString *fontPath = [NSString stringWithString:[(NSURL *)CFBridgingRelease(fontURL) path]];
	return fontPath;
}

//And I would call the function something like this
NSFont *font = [NSFont fontWithName:@"Menlo" size:12.0];
NSString *fontPath = [self filePathOfFont:font];
NSLog(@"%@", fontPath);

Please quote your operating system version for further help.

You do realise that this is an AppleScript forum, and not an Objective-C specific forum ?

Regards Mark