3.4. VectorFont Library

3.4.1. Vector Fonts Description

Vector fonts, also known as outline fonts, define glyphs with vector images instead of bitmaps. The main advantage of vector fonts is that they can be scaled to any size with the same quality (no pixelation).

3.4.2. Aim of the Library

The VectorFont Foundation Library has been designed as an extension of the MicroUI library to handle vector fonts. It provides methods to draw strings with TrueType fonts and apply different sizes, colors, opacity levels, and gradients at runtime.

The main advantages of using TrueType fonts over MicroUI fonts:

  • no need to embed a font for each size; the font height can be changed at runtime without loss of quality;
  • rendered by GPU.

Note

This library does not depend on the VGLite library; however, a part of its implementation (C code) depends on the vg_lite library.

3.4.3. Importing the Library

The library can be retrieved by adding the following dependency to your module.ivy:

<dependency org="ej.api" name="vector-font" rev="0.2.0"/>

3.4.4. The Java API

3.4.4.1. Font Loading

A TrueType font are loaded by the static method TrueTypeFont.getTrueTypeFont(string fontPath).

For instance, to load LiberationSans_Bold.tff from src/resources/ttf/ directory:

VectorFont font = VectorFont.getTrueTypeFont("/ttf/LiberationSans_Bold.ttf");

As for all resources, the fonts need to be referenced in a .resources.list file to be embedded in the application.

For instance, here is the content of src/resources/ttf/fonts.resources.list:

# Resources list

/ttf/LiberationSans_Bold.ttf

Note

A loaded font is cached, so getting the same font several times does not increase memory usage.

3.4.4.2. Text Drawing

All the drawing methods are static methods of VectorFontPainter. This class is the equivalent of Painter in MicroUI.

Strings can be drawn on a straight baseline with drawString methods or on a curved baseline (a circle arc) with drawStringArc. As in MicroUI drawing methods, x and y coordinates refer to the top-left corner of the string bounding box. The height of the font can be set with the size argument. It is the height of the glyph in pixels, including spacing.

drawString(GraphicsContext gc, VectorFont font, float size, String string, int x, int y);

The string width can be obtained by calling stringWidth on the font:

font.stringWidth(float size, String string);

When drawing string on an arc, x and y coordinates refer to the top-left corner of the circle, and diameter is the diameter of this circle in pixels. angle is the angle in degrees of the first character of the string in the counterclockwise direction.

drawStringArc(GraphicsContext gc, VectorFont font, int size, String string, int x, int y, int diameter, float angle);

The orientation of the string can be changed with the out parameter.

../_images/freetype_out_example.png
drawStringArc(GraphicsContext gc, VectorFont font, float size, String string, int x, int y, int diameter, float angle, boolean out);

There are several variations for each of these methods to change opacity or use gradient colors.

Note

You can implement your transformation algorithm for a custom string, drawing the string character by character with Single Character Drawing.

3.4.4.3. Changing Color, Opacity and Using Gradients

The color used to draw a string is the color set to the GraphicContext. Opacity can be changed by passing an alpha value as the argument. This value is an integer from 0 (fully transparent) to 255 (fully opaque). When not set, the color is considered opaque.

drawString(GraphicsContext gc, VectorFont font, String string, int size, int x, int y, int opacity);
drawStringArc(GraphicsContext gc, VectorFont font, String string, int size, int x, int y, int diameter, float angle, int opacity);

A multiple linear gradient can be applied to the text using the LinearGradient class. The gradient is defined between two points (startX, startY) and (endX, endY).

LinearGradient gradient = new LinearGradient(int startX, int startY, int endX, int endY, int[] fractions, int[] colors);

The colors array contains the colors in ARGB format to apply from start to end, and the fractions array defines the positions of the colors to apply along the gradient line 0 meaning the start and 255 the end. The length of fractions is the same as colors and it contains integers in ascending order from 0 to 255.

../_images/gradients.png

The gradient can then be applied to the text, passing it as the argument:

drawStringArc(GraphicsContext gc, VectorFont font, float size, String string, int x, int y, int diameter, float angle, LinearGradient gradient);
drawStringArc(GraphicsContext gc, VectorFont font, float size, String string, int x, int y, int diameter, float angle, LinearGradient gradient, boolean out);

LinearGradient should be closed when not used anymore to free memory using its close() method.

Warning

The same instance of LinearGradient must not be used in several threads at the same time. This class is not thread-safe to avoid synchronization overhead.

3.4.4.4. Using char[] Instead of String

Each of these methods also exists, taking a character array as the argument instead of a string. These methods avoid a copy of the internal char[] of String and can pass a subarray using offset and length arguments.

// drawString equivalents
drawChars(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y);
drawChars(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int opacity);
drawChars(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, LinearGradient gradient);

// drawStringArc equivalents
drawCharsArc(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int diameter, float angle);
drawCharsArc(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int diameter, float angle, boolean out);
drawCharsArc(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int diameter, float angle, int opacity);
drawCharsArc(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int diameter, float angle, int opacity, boolean out);
drawCharsArc(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int diameter, float angle, LinearGradient gradient);
drawCharsArc(GraphicsContext gc, VectorFont font, float size, char[] chars, int offset, int length, int x, int y, int diameter, float angle, LinearGradient gradient, boolean out);

3.4.4.5. Single Character Drawing

It is also possible to draw a single character using the drawChar method. As for drawString, you can define the opacity or the gradient to apply.

drawChar(GraphicsContext gc, VectorFont font, float size, char character, Matrix matrix, int opacity);
drawChar(GraphicsContext gc, VectorFont font, float size, char character, Matrix matrix, LinearGradient gradient);

Matrix is a 2D transformation matrix, just like vg_lite_matrix from VG Lite Library. It is used to set the position, orientation, and scale of the character in the graphic context. The following transformations can be applied:

  • identity: To set a matrix to identity.
  • translate: Translates a matrix.
  • init: A shortcut for identity + translate.
  • scale: Scales a matrix.

For drawing a string character by character, you may need to know the width of the characters. The character width can be obtained by calling charWidth on the font:

font.charWidth(float size, char character);

For example, the following code draws the given string at the position (x, y):

public void drawCustomString(GraphicsContext gc, VectorFont font, float size, String string, int x, int y) {
    final char[] characters = string.toCharArray();
    final Matrix matrix = new Matrix();
    final int alpha = 255;

    matrix.init(x, y);
    int advance = 0;

    for (char character : characters) {
        VectorFontPainter.drawChar(gc, font, size, character, matrix, alpha);
        advance += font.charWidth(size, character);
        matrix.translate(advance, 0);
    }
}