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