Skip to content

Commit 69919e1

Browse files
schodetlaurensvalk
authored andcommitted
pbio: Implement text drawing.
Use only one font for the moment, Terminus Font, 8x16 pixels size. A script is included to generate the font source using freetype-py. Only handle ASCII characters as discussed. Antialiasing is not that great with the limited number of gray levels on the EV3, so use only monochrome font, which works great thanks to hinting. Refs: pybricks/support#2154
1 parent d36c1ba commit 69919e1

File tree

10 files changed

+1167
-0
lines changed

10 files changed

+1167
-0
lines changed

bricks/_common/sources.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
207207
src/drivebase.c \
208208
src/error.c \
209209
src/geometry.c \
210+
src/image/font_liberationsans_regular_14.c \
211+
src/image/font_terminus_normal_16.c \
210212
src/image/image.c \
211213
src/imu.c \
212214
src/int_math.c \

lib/pbio/include/pbio/font.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 Nicolas Schodet
3+
4+
/**
5+
* @addtogroup Font Text font.
6+
* @{
7+
*/
8+
9+
#ifndef _PBIO_FONT_H_
10+
#define _PBIO_FONT_H_
11+
12+
#include <pbio/config.h>
13+
14+
#include <stdint.h>
15+
16+
/**
17+
* Single glyph.
18+
*/
19+
typedef struct _pbio_font_glyph_t {
20+
/**
21+
* Width of glyph bitmap.
22+
*/
23+
uint8_t width;
24+
/**
25+
* Height of glyph bitmap.
26+
*/
27+
uint8_t height;
28+
/**
29+
* Advance to next character in horizontal direction.
30+
*/
31+
uint8_t advance;
32+
/**
33+
* Horizontal distance between pen position and leftmost bitmap column.
34+
* Positive values goes left.
35+
*/
36+
int8_t left;
37+
/**
38+
* Vertical distance between baseline and topmost bitmap row. Positive
39+
* values goes up.
40+
*/
41+
int8_t top;
42+
/**
43+
* Index of bitmap start in data table.
44+
*/
45+
uint16_t data_index;
46+
/**
47+
* Start index of kerning values in kerning table. The Stop index is the
48+
* start index of the next glyph.
49+
*/
50+
uint16_t kerning_index;
51+
} pbio_font_glyph_t;
52+
53+
/**
54+
* Kerning information for a glyph.
55+
*/
56+
typedef struct _pbio_font_kerning_t {
57+
/**
58+
* Previous glyph.
59+
*/
60+
uint8_t previous;
61+
/**
62+
* Kerning from previous glyph to current one.
63+
*/
64+
int8_t kerning;
65+
} pbio_font_kerning_t;
66+
67+
/**
68+
* Font.
69+
*
70+
* Every bitmap data is composed of one or several rows as indicated in the
71+
* glyph structure, with the top row first. Eight pixels are packed into
72+
* a bytes, with the first leftmost pixel in the most significant bit. The
73+
* bitmap width is padded to the next multiple of eight.
74+
*/
75+
typedef struct _pbio_font_t {
76+
/**
77+
* First glyph.
78+
*/
79+
uint8_t first;
80+
/**
81+
* Last glyph.
82+
*/
83+
uint8_t last;
84+
/**
85+
* Line height, number of pixels between consecutive baselines.
86+
*/
87+
uint8_t line_height;
88+
/**
89+
* Maximum value of glyph top.
90+
*/
91+
int8_t top_max;
92+
/**
93+
* Glyph table. Must contain a dummy last glyph for the last kerning stop
94+
* index.
95+
*/
96+
const pbio_font_glyph_t *glyphs;
97+
/**
98+
* Data table with bitmaps.
99+
*/
100+
const uint8_t *data;
101+
/**
102+
* Kerning table, may be NULL if no kerning.
103+
*/
104+
const pbio_font_kerning_t *kernings;
105+
} pbio_font_t;
106+
107+
#if PBIO_CONFIG_IMAGE
108+
109+
extern const pbio_font_t pbio_font_liberationsans_regular_14;
110+
extern const pbio_font_t pbio_font_terminus_normal_16;
111+
112+
#endif // PBIO_CONFIG_IMAGE
113+
114+
#endif // _PBIO_FONT_H_
115+
116+
/** @} */

lib/pbio/include/pbio/image.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
#define _PBIO_IMAGE_H_
1111

1212
#include <pbio/config.h>
13+
#include <pbio/font.h>
1314

1415
#include <stdint.h>
16+
#include <stddef.h>
1517

1618
/**
1719
* Image container.
@@ -51,6 +53,28 @@ typedef struct _pbio_image_t {
5153
int stride;
5254
} pbio_image_t;
5355

56+
/**
57+
* Coordinates of a rectangle.
58+
*/
59+
typedef struct _pbio_image_rect_t {
60+
/**
61+
* X coordinate.
62+
*/
63+
int x;
64+
/**
65+
* Y coordinate.
66+
*/
67+
int y;
68+
/**
69+
* Number of columns.
70+
*/
71+
int width;
72+
/**
73+
* Number of rows.
74+
*/
75+
int height;
76+
} pbio_image_rect_t;
77+
5478
#if PBIO_CONFIG_IMAGE
5579

5680
void pbio_image_init(pbio_image_t *image, uint8_t *pixels, int width,
@@ -99,6 +123,12 @@ void pbio_image_draw_circle(pbio_image_t *image, int x, int y, int r,
99123
void pbio_image_fill_circle(pbio_image_t *image, int x, int y, int r,
100124
uint8_t value);
101125

126+
void pbio_image_draw_text(pbio_image_t *image, const pbio_font_t *font, int x,
127+
int y, const char *text, size_t text_len, uint8_t value);
128+
129+
void pbio_image_bbox_text(const pbio_font_t *font, const char *text,
130+
size_t text_len, pbio_image_rect_t *rect);
131+
102132
#endif // PBIO_CONFIG_IMAGE
103133

104134
#endif // _PBIO_IMAGE_H_

lib/pbio/src/image/Makefile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this Makefile to generate font files.
2+
3+
FONTCONVERT = ../../tools/fontconvert.py
4+
5+
LIBERATION_LICENSE = "OFL-1.1-RFN"
6+
LIBERATION_COPYRIGHT = \
7+
--copyright "Digitized data copyright (c) 2010 Google Corporation" \
8+
--copyright " with Reserved Font Arimo, Tinos and Cousine." \
9+
--copyright "Copyright (c) 2012 Red Hat, Inc." \
10+
--copyright " with Reserved Font Name Liberation."
11+
LIBERATION_SANS_REGULAR = /usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf
12+
13+
TERMINUS_LICENSE = "OFL-1.1-RFN"
14+
TERMINUS_COPYRIGHT = \
15+
--copyright "Copyright (c) 2010-2014 Dimitar Toshkov Zhekov," \
16+
--copyright ' with Reserved Font Name "Terminus Font".'
17+
TERMINUS_NORMAL = /usr/share/fonts/opentype/terminus/terminus-normal.otb
18+
19+
all: font_liberationsans_regular_14.c font_terminus_normal_16.c
20+
21+
font_liberationsans_regular_14.c: $(LIBERATION_SANS_REGULAR) $(FONTCONVERT)
22+
python3 $(FONTCONVERT) $< 14 --license $(LIBERATION_LICENSE) $(LIBERATION_COPYRIGHT) > $@
23+
24+
font_terminus_normal_16.c: $(TERMINUS_NORMAL) $(FONTCONVERT)
25+
python3 $(FONTCONVERT) $< 16 --license $(TERMINUS_LICENSE) $(TERMINUS_COPYRIGHT) > $@

0 commit comments

Comments
 (0)