Files
esDashboard/src/display/ui/text/Fonts.cpp
T
2025-12-30 14:25:58 +00:00

120 lines
3.7 KiB
C++

#include "display/ui/text/Fonts.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include <stdexcept>
#include <iostream>
#include <filesystem>
#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<Library>())
{
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> face = std::make_unique<Face>();
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