#include "display/ui/text/Fonts.h" #include #include FT_FREETYPE_H #include #include #include #include "helpers/Paths.h" namespace display::ui::text { struct Fonts::Library { FT_Library library = nullptr; }; struct Fonts::Face { FT_Face face = nullptr; }; Fonts::Fonts() : library(std::make_unique()) { if (FT_Init_FreeType(&library->library)) throw std::runtime_error("FT_Init_FreeType failed"); loadAllFonts(); } Fonts::~Fonts() { for (auto &[k, v] : fonts) if (v->face) FT_Done_Face(v->face); if (library->library) FT_Done_FreeType(library->library); } void Fonts::loadAllFonts() { loadFonts("/usr/share/fonts/truetype"); loadFonts("/usr/share/esdashboard/fonts"); // loadFonts(helpers::initPaths().exeDir); } void Fonts::loadFonts(const std::string &path) { if (std::filesystem::exists(path)) { for (auto &p : std::filesystem::recursive_directory_iterator(path)) { if (p.path().extension() == ".ttf" || p.path().extension() == ".otf") { std::string path = p.path().string(); std::string filename = p.path().stem().string(); // Можно сразу создавать Fonts для стандартных размеров, например: 10,12,14,16,18,24 for (int sz : {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 24, 36, 72}) { Font key{filename, sz}; std::unique_ptr face = std::make_unique(); if (FT_New_Face(library->library, path.c_str(), 0, &face->face)) throw std::runtime_error("FT_New_Face failed"); FT_Set_Pixel_Sizes(face->face, 0, sz); fonts.emplace(key, std::move(face)); } } } } } const Glyph &Fonts::getGlyph(char ch, const Font &font) { GlyphKey key{ch, font}; auto gph = glyphs.find(key); if (gph != glyphs.end()) return gph->second; auto fnt = fonts.find(font); if (fnt == fonts.end()) { // Если нет, можно использовать какой-нибудь дефолтный шрифт fnt = fonts.begin(); } FT_Face face = fnt->second->face; if (!face) throw std::runtime_error("Fonts not initialized!"); if (FT_Load_Char(face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO)) throw std::runtime_error("FT_Load_Char failed"); FT_GlyphSlot g = face->glyph; Glyph glyph; glyph.width = g->bitmap.width; glyph.height = g->bitmap.rows; glyph.bearingX = g->bitmap_left; glyph.bearingY = g->bitmap_top; glyph.advance = g->advance.x >> 6; // glyph.buffer.assign(g->bitmap.buffer, g->bitmap.buffer + g->bitmap.width * g->bitmap.rows); glyph.buffer.resize(glyph.width * glyph.height, 0); const FT_Bitmap &bm = g->bitmap; for (int y = 0; y < bm.rows; ++y) { for (int x = 0; x < bm.width; ++x) { int byteIndex = y * bm.pitch + x / 8; int bitIndex = 7 - (x % 8); uint8_t bit = (bm.buffer[byteIndex] >> bitIndex) & 1; glyph.buffer[y * bm.width + x] = bit ? 255 : 0; } } return glyphs.emplace(key, std::move(glyph)).first->second; } } // namespace display::ui::text