Fork us on GitHub

Cool Text Effects for Your Mobile App on iPhone (iOS), Android etc.

Leverage FontBox to create meme style of text effects
Post Image

Cool Text Effects for Your Mobile App on iPhone (iOS), Android etc.

FontBox is a mature java library for loading, manipulating, and rendering fonts in Java. It gives you direct access to the font glyphs so that you can perform effects or transformations on them. A couple of years ago, I ported FontBox to Codename One, but since CN1 didn’t yet include support for drawing shapes, I made it dependent upon the CN1Pisces library, which did support drawing shapes. This was cool but it had some major limitations; the main one being that FontBox fonts could only be used to draw strings on Pisces graphics contexts, which can only be rendered to an image - not directly to the screen. This meant that you couldn’t just use a FontBox font in your app (e.g. in a label or a button). You could only use it to write on an image.

Fast forward to the present day, when Codename One supports drawing shapes "natively" on all major platforms, I felt is was time to revamp this library so that it integrates better with Codename One. My goal was to be able to use a FontBox font interchangeably with "normal" fonts. E.g. for a label, button, text field, graphics context, etc…​ The motivation for this update came as I was developing the "Meme Maker" demo. I needed to draw some text that was filled white but had a black outline. Built-in fonts don’t have this ability, but since FontBox provides direct access to the font glyphs as paths (i.e. lines and curves) I could fairly easily create a font that had both fill and stroke. That’s just what I did, with the new TTFFont class.

What can TTFFont do that Font cannot?

TTFFont is a subclass of CustomFont which is itself a subclass of com.codename1.ui.Font. Therefore it can be used in any place that a standard font is used. Why would you do this?

TTFFont supports stroking, filling, or both, with different colors. E.g. You can create a font that is stroked with white, but filled with black. And you can specify the width of the stroke just as you would a normal shape.

Stroked and filled text
Figure 1. Stroked and filled text

TTFFont supports both horizontal and vertical scaling, so you can make your text really skinny, or really wide, depending on what your requirements are. This also enables you to size text to fit a space exactly.

Stretched text
Figure 2. Stretched text
Compressed text
Figure 3. Compressed text

TTFFont can load a TTF file from storage, file system, resources, or just from a plain old InputStream. This means that you can load fonts dynamically over a network if you want.

Drawbacks

Since TTFFonts are actually rendered in CN1 as shapes, they will be slower than built-in fonts, which are rendered natively by the platform. Therefore, you should only use TTFFont in cases where you require its extra capabilities. That said, there was no noticeable "lag" introduced in the Meme Maker app by my use of TTFFont.

Usage Examples

Loading TTF File

From InputStream:

TTFFont font = TTFFont.createFont("MyFont", inputStream);

From Resources:

TTFFont font = TTFFont.createFont("MyFont", "/MyFont.ttf");

From Storage/URL:

TTFFont font = TTFFont.createFontToStorage("MyFont",
    "font_MyFont.ttf",
    "http://example.com/MyFont.ttf"
);

From File System/URL:

TTFFont font = TTFFont.createFontToFileSystem("MyFont",
    FileSystemStorage.getInstance().getAppHomePath()+"/fonts/MyFont.ttf",
    "http://example.com/MyFont.ttf"
);

From Cache:

TTFFont font = TTFFont.getFont("MyFont", 12);

Setting Font for Style

myLabel.getAllStyles().setFont(font);

Getting Particular Size Font

font = font.deriveFont(24); // get size 24 font.

Horizontal and Vertical Scaling

font = font.deriveScaled(0.5f, 1.5f);
    // scaled 50% horizontal, and 150% vertical

font = font.deriveHorizontalScaled(0.5f); // scaled 50% horizontally

font = font.deriveVerticalScaled(0.5f); // scaled 50% vertically

Stroking and Filling

font = font.deriveStroked(Stroke(1f, Stroke.CAP_BUTT, Stroke.JOIN_MITER, 1f), #ff0000);
    // Stroke with red 1px outline

font = font.deriveStroked(Stroke(1f, Stroke.CAP_BUTT, Stroke.JOIN_MITER, 1f), null);
    // Stroked - stroke color determined by graphics context's current color.. e.g. defers to Style's foreground color

font = font.deriveStroked(null, 0x0);
    // Not stroked

font = font.deriveFilled(true, null);
    // Filled - fill color determined by graphics context's current color.. e.g. defers to Style's foreground color

font = font.deriveFilled(true, 0x00ff00);
    // Filled with green

font = font.deriveFilled(false, null);
    // Not filled

Antialias

font = font.deriveAntialias(true);
    // Should be rendered antialiased

font = font.deriveAntialias(false);
    // should be rendered without antialias.

Drawing Directly on Graphics Context

font.drawString(g, "Hello world", x, y);

// Or ...
g.setFont(font);
g.drawString("Hello world", x, y);

Appending to existing GeneralPath

font.draw(path, "Hello world", x, y, 1f /*opacity*/);

More About CN1FontBox

For more information about CN1FontBox, check out the CN1FontBox github repository. The best way to install it is through the "Extensions" section of the Codename One Settings for your project.

Share this Post:

Posted by Steve Hannah

Steve writes software for Codename One. He is an open source enthusiast who loves to tinker with new technologies.