ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
font.cpp
Go to the documentation of this file.
1#include "font.h"
2
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6
7namespace esphome {
8namespace font {
9
10static const char *const TAG = "font";
11
12// Compare the char at the string position with this char.
13// Return true if this char is less than or equal the other.
14bool Glyph::compare_to(const uint8_t *str) const {
15 // 1 -> this->char_
16 // 2 -> str
17 for (uint32_t i = 0;; i++) {
18 if (this->a_char[i] == '\0')
19 return true;
20 if (str[i] == '\0')
21 return false;
22 if (this->a_char[i] > str[i])
23 return false;
24 if (this->a_char[i] < str[i])
25 return true;
26 }
27 // this should not happen
28 return false;
29}
30int Glyph::match_length(const uint8_t *str) const {
31 for (uint32_t i = 0;; i++) {
32 if (this->a_char[i] == '\0')
33 return i;
34 if (str[i] != this->a_char[i])
35 return 0;
36 }
37 // this should not happen
38 return 0;
39}
40void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const {
41 *x1 = this->offset_x;
42 *y1 = this->offset_y;
43 *width = this->width;
44 *height = this->height;
45}
46
47Font::Font(const Glyph *data, int data_nr, int baseline, int height, int descender, int xheight, int capheight,
48 uint8_t bpp)
49 : glyphs_(ConstVector(data, data_nr)),
50 baseline_(baseline),
51 height_(height),
52 descender_(descender),
53 linegap_(height - baseline - descender),
54 xheight_(xheight),
55 capheight_(capheight),
56 bpp_(bpp) {}
57int Font::match_next_glyph(const uint8_t *str, int *match_length) const {
58 int lo = 0;
59 int hi = this->glyphs_.size() - 1;
60 while (lo != hi) {
61 int mid = (lo + hi + 1) / 2;
62 if (this->glyphs_[mid].compare_to(str)) {
63 lo = mid;
64 } else {
65 hi = mid - 1;
66 }
67 }
68 *match_length = this->glyphs_[lo].match_length(str);
69 if (*match_length <= 0)
70 return -1;
71 return lo;
72}
73#ifdef USE_DISPLAY
74void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) {
75 *baseline = this->baseline_;
76 *height = this->height_;
77 int i = 0;
78 int min_x = 0;
79 bool has_char = false;
80 int x = 0;
81 while (str[i] != '\0') {
82 int match_length;
83 int glyph_n = this->match_next_glyph((const uint8_t *) str + i, &match_length);
84 if (glyph_n < 0) {
85 // Unknown char, skip
86 if (!this->get_glyphs().empty())
87 x += this->get_glyphs()[0].advance;
88 i++;
89 continue;
90 }
91
92 const Glyph &glyph = this->glyphs_[glyph_n];
93 if (!has_char) {
94 min_x = glyph.offset_x;
95 } else {
96 min_x = std::min(min_x, x + glyph.offset_x);
97 }
98 x += glyph.advance;
99
100 i += match_length;
101 has_char = true;
102 }
103 *x_offset = min_x;
104 *width = x - min_x;
105}
106void Font::print(int x_start, int y_start, display::Display *display, Color color, const char *text, Color background) {
107 int i = 0;
108 int x_at = x_start;
109 int scan_x1, scan_y1, scan_width, scan_height;
110 while (text[i] != '\0') {
111 int match_length;
112 int glyph_n = this->match_next_glyph((const uint8_t *) text + i, &match_length);
113 if (glyph_n < 0) {
114 // Unknown char, skip
115 ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]);
116 if (!this->get_glyphs().empty()) {
117 uint8_t glyph_width = this->get_glyphs()[0].advance;
118 display->filled_rectangle(x_at, y_start, glyph_width, this->height_, color);
119 x_at += glyph_width;
120 }
121
122 i++;
123 continue;
124 }
125
126 const Glyph &glyph = this->get_glyphs()[glyph_n];
127 glyph.scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height);
128
129 const uint8_t *data = glyph.data;
130 const int max_x = x_at + scan_x1 + scan_width;
131 const int max_y = y_start + scan_y1 + scan_height;
132
133 uint8_t bitmask = 0;
134 uint8_t pixel_data = 0;
135 uint8_t bpp_max = (1 << this->bpp_) - 1;
136 auto diff_r = (float) color.r - (float) background.r;
137 auto diff_g = (float) color.g - (float) background.g;
138 auto diff_b = (float) color.b - (float) background.b;
139 auto diff_w = (float) color.w - (float) background.w;
140 auto b_r = (float) background.r;
141 auto b_g = (float) background.g;
142 auto b_b = (float) background.b;
143 auto b_w = (float) background.w;
144 for (int glyph_y = y_start + scan_y1; glyph_y != max_y; glyph_y++) {
145 for (int glyph_x = x_at + scan_x1; glyph_x != max_x; glyph_x++) {
146 uint8_t pixel = 0;
147 for (int bit_num = 0; bit_num != this->bpp_; bit_num++) {
148 if (bitmask == 0) {
149 pixel_data = progmem_read_byte(data++);
150 bitmask = 0x80;
151 }
152 pixel <<= 1;
153 if ((pixel_data & bitmask) != 0)
154 pixel |= 1;
155 bitmask >>= 1;
156 }
157 if (pixel == bpp_max) {
158 display->draw_pixel_at(glyph_x, glyph_y, color);
159 } else if (pixel != 0) {
160 auto on = (float) pixel / (float) bpp_max;
161 auto blended = Color((uint8_t) (diff_r * on + b_r), (uint8_t) (diff_g * on + b_g),
162 (uint8_t) (diff_b * on + b_b), (uint8_t) (diff_w * on + b_w));
163 display->draw_pixel_at(glyph_x, glyph_y, blended);
164 }
165 }
166 }
167 x_at += glyph.advance;
168
169 i += match_length;
170 }
171}
172#endif
173
174} // namespace font
175} // namespace esphome
Lightweight read-only view over a const array stored in RODATA (will typically be in flash memory) Av...
Definition helpers.h:118
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
Definition display.h:336
void filled_rectangle(int x1, int y1, int width, int height, Color color=COLOR_ON)
Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,...
Definition display.cpp:105
void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) override
Definition font.cpp:74
void print(int x_start, int y_start, display::Display *display, Color color, const char *text, Color background) override
Definition font.cpp:106
const ConstVector< Glyph > & get_glyphs() const
Definition font.h:83
int match_next_glyph(const uint8_t *str, int *match_length) const
Definition font.cpp:57
uint8_t bpp_
Definition font.h:93
ConstVector< Glyph > glyphs_
Definition font.h:86
Font(const Glyph *data, int data_nr, int baseline, int height, int descender, int xheight, int capheight, uint8_t bpp=1)
Construct the font with the given glyphs.
Definition font.cpp:47
bool compare_to(const uint8_t *str) const
Definition font.cpp:14
const uint8_t * data
Definition font.h:36
void scan_area(int *x1, int *y1, int *width, int *height) const
Definition font.cpp:40
int match_length(const uint8_t *str) const
Definition font.cpp:30
const char * a_char
Definition font.h:35
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint8_t progmem_read_byte(const uint8_t *addr)
Definition core.cpp:70
uint8_t w
Definition color.h:42
uint8_t g
Definition color.h:34
uint8_t b
Definition color.h:38
uint8_t r
Definition color.h:30
uint16_t x
Definition tt21100.cpp:5