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:
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.
Figure 2. Drawing aligned text on screen using Bitstream Vera font
Here is an example of drawing a large font size on the 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.
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.
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);
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.
Figure 7. Drawing Comic Sans rotated text on screen