2024-05-08 22:22:47 +02:00
|
|
|
#include "text.h"
|
|
|
|
|
|
|
|
|
|
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
2024-05-09 01:16:08 +02:00
|
|
|
#include "common/image/font/imstb_truetype.h"
|
2024-05-08 22:22:47 +02:00
|
|
|
|
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "font/utf8.h"
|
|
|
|
|
|
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
|
#endif
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
2024-05-08 22:37:37 +02:00
|
|
|
#include "logger.h"
|
|
|
|
|
|
2024-05-09 01:16:08 +02:00
|
|
|
namespace image
|
2024-05-08 22:22:47 +02:00
|
|
|
{
|
|
|
|
|
TextDrawer::~TextDrawer()
|
|
|
|
|
{
|
|
|
|
|
if (has_font)
|
|
|
|
|
{
|
|
|
|
|
for (auto &v : font.chars)
|
|
|
|
|
free(v.bitmap);
|
|
|
|
|
font.chars.clear();
|
|
|
|
|
delete[] ttf_buffer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextDrawer::init_font(std::string font_path)
|
|
|
|
|
{
|
|
|
|
|
std::ifstream infile(font_path, std::ios::binary);
|
|
|
|
|
|
|
|
|
|
if (!infile.good())
|
|
|
|
|
return;
|
|
|
|
|
// get length of file
|
|
|
|
|
infile.seekg(0, std::ios::end);
|
|
|
|
|
size_t length = infile.tellg();
|
|
|
|
|
infile.seekg(0, std::ios::beg);
|
|
|
|
|
ttf_buffer = new uint8_t[length];
|
|
|
|
|
// read file
|
|
|
|
|
infile.read((char *)ttf_buffer, length);
|
|
|
|
|
|
|
|
|
|
stbtt_fontinfo fontp;
|
|
|
|
|
stbtt_InitFont(&fontp, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
|
|
|
|
|
|
|
|
|
|
stbtt_GetFontBoundingBox(&fontp, &font.x0, &font.y0, &font.x1, &font.y1);
|
|
|
|
|
stbtt_GetFontVMetrics(&fontp, &font.asc, &font.dsc, &font.lg);
|
|
|
|
|
|
|
|
|
|
font.fontp = fontp;
|
|
|
|
|
infile.close();
|
|
|
|
|
has_font = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextDrawer::draw_text(Image &img, int xs0, int ys0, std::vector<double> color, int s, std::string text)
|
|
|
|
|
{
|
|
|
|
|
if (!has_font)
|
2024-05-08 22:37:37 +02:00
|
|
|
{
|
|
|
|
|
logger->error("Tried to draw text without having a font initialized!");
|
2024-05-08 22:22:47 +02:00
|
|
|
return;
|
2024-05-08 22:37:37 +02:00
|
|
|
}
|
2024-05-08 22:22:47 +02:00
|
|
|
int CP = 0;
|
|
|
|
|
std::vector<char> cstr(text.c_str(), text.c_str() + text.size() + 1);
|
|
|
|
|
char *c = cstr.data();
|
|
|
|
|
float SF = stbtt_ScaleForPixelHeight(&font.fontp, s);
|
|
|
|
|
int BL = SF * font.y1;
|
|
|
|
|
|
|
|
|
|
char_el info;
|
|
|
|
|
|
|
|
|
|
while (c < c + cstr.size())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
info.char_nb = utf8::next(c, c + cstr.size());
|
|
|
|
|
}
|
|
|
|
|
catch (utf8::invalid_utf8 &)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (info.char_nb == '\0')
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (info.char_nb == 0xA)
|
|
|
|
|
{ // EOL
|
|
|
|
|
ys0 += SF * (font.asc - font.dsc + font.lg);
|
|
|
|
|
CP = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool f = false;
|
|
|
|
|
for (unsigned int k = 0; k < font.chars.size(); k++)
|
|
|
|
|
if (font.chars[k].char_nb == info.char_nb)
|
|
|
|
|
{
|
|
|
|
|
if (font.chars[k].size != s)
|
|
|
|
|
{
|
|
|
|
|
font.chars.erase(font.chars.begin() + k);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
f = true;
|
|
|
|
|
info = font.chars[k];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
|
{
|
|
|
|
|
// bitmap = stbtt_GetGlyphBitmap(&font.fontp, 0, SF, info.char_nb, &info.w, &info.h, 0, 0);
|
|
|
|
|
info.glyph_nb = stbtt_FindGlyphIndex(&font.fontp, info.char_nb);
|
|
|
|
|
stbtt_GetGlyphBox(&font.fontp, info.glyph_nb, &info.cx0, &info.cy0, &info.cx1, &info.cy1);
|
|
|
|
|
stbtt_GetGlyphBitmapBox(&font.fontp, info.glyph_nb, SF, SF, &info.ix0, &info.iy0, &info.ix1, &info.iy1);
|
|
|
|
|
stbtt_GetGlyphHMetrics(&font.fontp, info.glyph_nb, &info.advance, &info.lsb);
|
|
|
|
|
info.w = abs(info.ix1 - info.ix0);
|
|
|
|
|
info.h = abs(info.iy1 - info.iy0);
|
|
|
|
|
info.bitmap = (unsigned char *)malloc(info.w * info.h);
|
|
|
|
|
info.size = s;
|
|
|
|
|
memset(info.bitmap, 0, info.w * info.h);
|
|
|
|
|
stbtt_MakeGlyphBitmap(&font.fontp, info.bitmap, info.w, info.h, info.w, SF, SF, info.glyph_nb);
|
|
|
|
|
font.chars.push_back(info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pos = 0;
|
|
|
|
|
for (int j = 0; j < info.h; ++j)
|
|
|
|
|
for (int i = 0; i < info.w; ++i)
|
|
|
|
|
{
|
|
|
|
|
unsigned char m = info.bitmap[pos];
|
|
|
|
|
int x = xs0 + i + CP + SF * info.lsb, y = j + BL - info.cy1 * SF + ys0;
|
|
|
|
|
unsigned int pos2 = y * img.width() + x;
|
|
|
|
|
if (m != 0 && pos2 < img.width() * img.height())
|
|
|
|
|
{
|
|
|
|
|
float mf = m / 255.0;
|
|
|
|
|
std::vector<double> col = {(color[0] - img.getf(0, pos2)) * mf + img.getf(0, pos2),
|
|
|
|
|
img.channels() > 1 ? ((color[1] - img.getf(1, pos2)) * mf + img.getf(1, pos2)) : 1,
|
|
|
|
|
img.channels() > 2 ? ((color[2] - img.getf(2, pos2)) * mf + img.getf(2, pos2)) : 1,
|
|
|
|
|
img.channels() > 3 ? ((color[3] - img.getf(3, pos2)) * mf + img.getf(3, pos2)) : 1};
|
|
|
|
|
img.draw_pixel(x, y, col);
|
|
|
|
|
}
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
// if (!f)
|
|
|
|
|
// stbtt_FreeBitmap(bitmap, font.fontp.userdata);
|
|
|
|
|
|
|
|
|
|
CP += SF * info.advance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|