Fork me on GitHub

Updated Drawing Text on OLED Chip SSD1306 Using FreeType2


We are updating the previous post on drawing text, since we realized we needed to fix a major display bug in pixel locating the text. In addition to that we updated the API for drawing text to return a bounding box around the drawn text so that the developer can know the pixel coordinates of where the text was drawn in the framebuffer. We also updated the bit-dump API to optionally add color to the terminal output.

The code in this post is as of git tag 0.6 or commit 50e836f9299f61a3fe2901f794d2131ade7c23be from Github.

BITDUMP COLOR

The bitdump API now automatically colors the 0’s as blue and the 1’s as red in the default ssd1306_framebuffer_bitdump() function. If the user sets use_color to true in the ssd1306_framebuffer_bitdump_custom() function the colors are set to blue and red for 0 and 1, respectively. There is currently no plan on supporting other color combinations.

DRAWING TEXT

To draw a font on a framebuffer, we chose to use FreeType2 as it is open source, and supports a variety of fonts. It also lends itself well to drawing the font directly to our framebuffer memory image.

Just by following the FreeType2 tutorial we were able to implement the ssd1306_framebuffer_draw_text() and the ssd1306_framebuffer_draw_text_extra() functions.

We have abstracted out the FreeType2 usage, so that if in the future we choose to change the dependency on FreeType2, we can without exposing the APIs of the library to idiosyncrasies of FreeType2.

The simplest way to draw a string of text at (x,y) coordinates is to use the ssd1306_framebuffer_draw_text() function, which will start drawing the text at (x,y) for the given font and font size, as shown below.

If the user provides a pointer to an ssd1306_framebuffer_box_t object as the optional last argument, the function returns the bounding box for the drawn text in the framebuffer. This contains the pixel coordinates of the rectangle in which the text has been drawn, and informs the user of the region where the pixels are drawn.

#include <ssd1306_graphics.h>

/* ... some initialization code ... */

/* create the framebuffer for a OLED screen 128x32 */
ssd1306_framebuffer_t *fbp = ssd1306_framebuffer_create(128, 32, NULL);

ssd1306_framebuffer_box_t bbox; // bounding box

// draw ABCDeF with the default font and font size 4 at (x,y) of (32, 32)
ssd1306_framebuffer_draw_text(fbp, "ABCDeF", 0, 32, 32, SSD1306_FONT_DEFAULT, 4, &bbox);

ssd1306_framebuffer_bitdump(fbp);

fprintf(stderr,
    "Bounding box coordinates top: %d left: %d right: %d bottom %d",
    bbox.top, bbox.left, bbox.right, bbox.bottom);

The framebuffer now looks like:

Framebuffer dump on terminal for drawing text

Figure 1. Bitdump of the colored framebuffer on the terminal

As you can see above the default font (BitStream Vera) gets rendered onto the framebuffer as expected, and in the same way gets displayed on screen on the OLED device as seen in the image below.

We also note that the top and left of the bounding box are the same as the (x,y) coordinates at which the drawing of the text was requested. The right and bottom values denote the maximum pixel coordinates where the drawing completed. If you want to know where to draw the next string, these values can be useful to locate the position of the string correctly.

Drawing Text on the SSD1306 OLED Screen

Figure 2. Drawing aligned text on screen using Bitstream Vera font

Here is an example of drawing a large font size on the screen.

Drawing large font on the SSD1306 OLED Screen

Figure 3. Drawing a large font size on screen using the Bitstream Vera font

SUPPORTED FONT FACES

By default, the libssd1306 library supports the following fonts, and also allows the user to load their own font file. The package requirements for the default fonts require the user to install fonts-freefont-ttf and ttf-bitstream-vera. If the user wants to have access to Microsoft®’s TrueType fonts, they can install ttf-mscorefonts-installer using the package manager and get access to Microsoft® specific fonts like Arial and Comic Sans.

We shall show you examples of using the custom fonts below. Using the ssd1306_fontface_t enum type allows the user to not have to know where the font file is located, since we already know that as part of the installation packages. So we currently hard-code these locations in and map them to an enum. If the user wants to load their own font file they can use the SSD1306_FONT_CUSTOM option and the ssd1306_framebuffer_draw_text_extra() function which accepts custom options for drawing the text, including the font file location.

The default font paths are provided in the ssd1306_graphics.h header file.

If the user wants to draw using the Microsoft® TrueType font Comic Sans, they can use the following code example:

#include <ssd1306_graphics.h>
/* ... some initialization ... */

/* create the framebuffer for a OLED screen 128x32 */
ssd1306_framebuffer_t *fbp = ssd1306_framebuffer_create(128, 32, NULL);

// setup the options
ssd1306_graphics_options_t opts;
opts.type = SSD1306_OPT_FONT_FILE;
opts.value.font_file = "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf";
// call the draw_text_extra() function which accepts options
ssd1306_framebuffer_draw_text_extra(fbp. "ABCDeF", 0, 32, 32, SSD1306_FONT_CUSTOM, 4, &opts, 1);

The only difference between the ssd1306_framebuffer_draw_text() and ssd1306_framebuffer_draw_text_extra() functions is that the latter accepts custom options for font files, rotation of fonts and rotation of pixels.

ROTATING THE FONT

In some rare cases, we may want to draw a text at an angle such as for displaying logos, or just rotating a text on screen by say 30°. We can do that with the SSD1306_OPT_ROTATE_FONT option and provide the rotation angle in the rotation_degrees field. This uses the font transformation functions provided by FreeType2 internally, and is highly accurate.

Below is an example that uses both the custom font file option for Comic Sans and rotates it by 30°, as seen in the framebuffer output.

#include <ssd1306_graphics.h>
/* ... some initialization ... */

/* create the framebuffer for a OLED screen 128x32 */
ssd1306_framebuffer_t *fbp = ssd1306_framebuffer_create(128, 32, NULL);

ssd1306_framebuffer_box_t bbox; // bounding box
// setup the options
ssd1306_graphics_options_t opts[2];
opts[0].type = SSD1306_OPT_FONT_FILE;
opts[0].value.font_file = "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf";
opts[1].type = SSD1306_OPT_ROTATE_FONT;
opts[1].value.rotation_degrees = 30;
// call the draw_text_extra() function which accepts options
ssd1306_framebuffer_draw_text_extra(fbp. "ABCDeF", 0, 32, 32, SSD1306_FONT_CUSTOM, 4, opts, 2, &bbox);
// dump the framebuffer to screen
ssd1306_framebuffer_bitdump(fbp);
fprintf(stderr,
    "Bounding box coordinates top: %d left: %d right: %d bottom %d",
    bbox.top, bbox.left, bbox.right, bbox.bottom);

Below is the screenshot of the terminal displaying the rotation of the font and the usage of the Microsoft® Comic Sans font. As you may notice, that the bounding box is different in this example as the font selected is different and rotating the font changes the size of the box.

Framebuffer dump on terminal for drawing text with rotated font

Figure 4. Bitdump of the rotated Comic Sans font on the terminal

All the code snippets can be found in the examples/fb_graphics.c file.

ROTATING PIXELS

As shown in the previous post, we may want to rotate an image on the screen by using the pixel rotation function. We can absolutely use that feature for drawing text at different locations by rotating not just the font, but also the pixels.

Below is an example that uses both the custom font file option for Comic Sans and rotates it by 30°, and then rotates the drawing by 180° as seen in the framebuffer output.

Note that the SSD1306_OPT_ROTATE_PIXEL option only accepts multiples of 90° in the rotation_degrees field. Any other value will get ignored, and an error statement printed to the log.

#include <ssd1306_graphics.h>
/* ... some initialization ... */

/* create the framebuffer for a OLED screen 128x32 */
ssd1306_framebuffer_t *fbp = ssd1306_framebuffer_create(128, 32, NULL);

// setup the options
ssd1306_graphics_options_t opts[1];
opts[0].type = SSD1306_OPT_ROTATE_PIXEL;
opts[0].value.rotation_degrees = 180;
// call the draw_text_extra() function which accepts options
ssd1306_framebuffer_draw_text_extra(fbp. "ABCDeF", 0, 0, 0, SSD1306_FONT_DEFAULT, 4, opts, 1);
// dump the framebuffer to screen
ssd1306_framebuffer_bitdump(fbp);

In Figure 5, you can see an example of the pixels rotated by 180° to flip the drawing of the text.

Framebuffer dump on terminal for drawing text with rotated pixels

Below is the code for rotating both the font and the pixels by 30° each.

#include <ssd1306_graphics.h>
/* ... some initialization ... */

/* create the framebuffer for a OLED screen 128x32 */
ssd1306_framebuffer_t *fbp = ssd1306_framebuffer_create(128, 32, NULL);

// setup the options
ssd1306_graphics_options_t opts[2];
opts[0].type = SSD1306_OPT_ROTATE_FONT;
opts[0].value.rotation_degrees = 18;
opts[1].type = SSD1306_OPT_ROTATE_PIXEL;
opts[1].value.rotation_degrees = 30;
// call the draw_text_extra() function which accepts options
ssd1306_framebuffer_draw_text_extra(fbp. "ABCDeF", 0, 0, 0, SSD1306_FONT_DEFAULT, 4, opts, 2);
// dump the framebuffer to screen
ssd1306_framebuffer_bitdump(fbp);

Framebuffer dump on terminal for drawing text with rotated font and rotated pixels

Figure 6. Bitdump of the rotated default font and rotated pixels on the terminal

Figure 7 is an example of using Comic Sans and rotating the font and pixels each by 30 degrees on the OLED screen.

Drawing Text on the SSD1306 OLED Screen

Figure 7. Drawing Comic Sans rotated text on screen