Search code examples
javascriptapplescriptjavascript-automation

jxa - Getting NSAttributedString font metrics in JavaScript for Automation


In macOS Sierra JavaScript for Automation, we can write:

// helvetica12Width :: String -> Num
function helvetica12Width(str) {
    return $.NSAttributedString.alloc.init.initWithString(
            str
        )
        .size.width;
}

to get metrics for a particular string in the default Helvetica 12. What I haven't yet managed to do is to pass in attributes for other fonts and font sizes, and get corresponding metrics for those.

Has anyone discovered an idiom/syntax that works here from JXA or AppleScript ?

Update: This is the kind of thing I have experimented with – clearly off the mark though, as variation in the font size/name values doesn't affect the return value:

(() => {
    'use strict';

    ObjC.import('AppKit');

    return $.NSAttributedString.alloc.init.initWithStringAttributes(
            "Substantiation", {
                'NSFontAttributeName': $.NSFont.fontWithNameSize('Helvetica', 24)
            }
        )
        .size.width
})();

Solution

  • Ah ... this seems to do it:

    (function () {
        'use strict';
    
        ObjC.import('AppKit');
    
        // show :: a -> String
        const show = x => JSON.stringify(x, null, 2);
    
        // stringSizeInFontAtPointSize :: String -> String -> Num
        //                                  -> {width:Num, height:Num}
        function stringSizeInFontAtPointSize(str, fontName, points) {
            return $.NSAttributedString.alloc.init.initWithStringAttributes(
                str, $({
                    'NSFont': $.NSFont.fontWithNameSize(fontName, points)
                })
            )
            .size;
        }
    
        // TEST -------------------------------------------------------------------
        return show([
            stringSizeInFontAtPointSize("hello World", "Geneva", 32),
            stringSizeInFontAtPointSize("hello World", "Geneva", 64),
            stringSizeInFontAtPointSize("hello World", "Helvetica", 64),
        ]);
    })();