Modern custom font guide?

Every discussion here about how to use a custom font is dated from 2010 or so.

Can anyone point out how to embed and use a custom font for modern JUCE?

Thanks.

1 Like

I’ve done it a few times, I will try to write up a guide. It’s sort of (but not super) convoluted to get working.

1 Like

That would be awesome. Something tells me I’m not the only one who would find it useful. Thanks.

It’s super simple with the Projucer. Just:

  • Add the TTF (or OTF etc) files to the Projucer project. By default it will add them in the BinaryData.
  • Use Typeface::createSystemTypefaceFor() to create the typeface and construct a font.

I’ve never had a problem doing this with a Meyer’s singleton, especially now they’re threadsafe to initialise in C++11. Let’s say you had a font WackyFont.otf and it has been added to the Projucer project. You can have a method to create this font:

static const Font& getWackyFont()
{
    static Font wacky (Font (Typeface::createSystemTypefaceFor (BinaryData::WackyFont_otf,
                                                                BinaryData::WackyFont_otfSize)));
    return wacky;
}

I usually add a method like this to my custom look-and-feel class. They you can get different sizes by doing things like getWackyFont().withHeight (255.0f) etc…

I’m sure there are other patterns that you can use as Typeface::createSystemTypefaceFor() returns a shared Typeface::Ptr.

BTW Watch out for font licenses as many include an exclusion for embedding like this and require a separate (often more costly) license…Slightly different context but there was the My Little Pony case recently…

7 Likes

Regarding the encoding of the font files to the binaryData file you can also use the BinaryBuilder (cf JUCE/extras/binarybuilder). I find it more practical than projucer for that, it makes it easy and fast to update the binaries, and name the binary file as you want

" Usage: BinaryBuilder  sourcedirectory targetdirectory targetclassname [optional wildcard pattern]\n\n"
                     " BinaryBuilder will find all files in the source directory, and encode them\n"
                     " into two files called (targetclassname).cpp and (targetclassname).h, which it\n"
                     " will write into the target directory supplied.\n\n"
                     " Any files in sub-directories of the source directory will be put into the\n"
                     " resultant class, but #ifdef'ed out using the name of the sub-directory (hard to\n"
                     " explain, but obvious when you try it...)\n";
3 Likes

Full example of embedding.
Here’s my FontAwesome wrapper …


1 Like

Thanks, everyone. It was much easier than I expected. I simply added the .otf file in Projucer, and then added this to my LookAndFeel:

Typeface::Ptr getTypefaceForFont(const Font& f) override
    {
        static Typeface::Ptr myFont = Typeface::createSystemTypefaceFor(BinaryData::uglyFont_otf,
                                                                 BinaryData::uglyFont_otfSize);
        return myFont;
    }

Thanks again, gents.

5 Likes

At some point in the past it was way more complicated :slight_smile:

1 Like

Yeah, when i said I’d post a guide to how I do it this was pretty much the meat of what I was going to show. When I do it however, I usually add an if/else inside the getTypeFaceForFont function that allows the method to pick the font I actually want (whether it’s an embedded font or existing system font) via Font::getTypefaceName() so I can use multiple fonts if needed instead of blindly returning my typeface (which may be what you want in your case).

This thread seems to be the most relevant one so I’ll continue with it.

Is getTypefaceForFont() really works? am I missing something?

I’m only able to use custom fonts when they’re explicitly set. (and I’d like my LookAndFeel to simplify this of course).

Here is a simple PIP to test this:
CustomFontPIP.h (198.0 KB)

Here is what I get when running it on macOS (I’ll test other platforms afterwards) -

I would’ve expected the custom font to show for all text components.

1 Like

I use setDefaultSansSerifTypeface(Fonts::SpartanMB::regular.getTypeface()); in the constructor of my LookAndFeel and that works perfectly, not sure if it’s the right way to do it though :wink:

1 Like

what OS are you using and what branch/juce commit?

(btw, here is similar thread with similar issue:
Embedding Custom Fonts OTF, TTF)
I’m hoping with this PIP to set a reliable test for this behavior that can be easily tested/reproduced.

1 Like

That method works for me with both Windows and macOS, using 5.4.3 master (technically it’s my own fork, but the changes I made are in places completely unrelated to fonts).

It seems this is an important part of actually applying the custom LAF/font to be defaulted:
LookAndFeel::setDefaultLookAndFeel (&customLookAndFeel);

I’ll update the PIP accordingly and test it under additional OSes.

2 Likes

Yes, I’m also doing that, forgot to mention it.

1 Like

I’ve always found dealing with custom fonts in JUCE confusing and unintuitive.

Thanks to this and the other thread linked I boiled it down to these 3 lines to set a new default font stored as Binary Data:

In my custom L&F constructor

Typeface::Ptr tface = Typeface::createSystemTypefaceFor(BinaryData::MontserratRegular_ttf, BinaryData::MontserratRegular_ttfSize);
setDefaultSansSerifTypeface (tface);

and then in Main::initialise() or MainComponent constructor:

LookAndFeel::setDefaultLookAndFeel (&customLookAndFeel);
7 Likes