#ifndef FONTBUILDER_H #define FONTBUILDER_H #include #include #include #include #include #include #include #include #include #include #include struct FontBuilder { /** resulting font */ struct Result { /** pixel data */ std::vector data; /** character x offset in pixel */ std::vector offsets; uint16_t w; uint8_t h; QImage img; void dump(const char* name) const { std::cout << "static const uint8_t " << name << "_data[] = {"; for (uint8_t i : data) { std::cout << (int) i << ","; } std::cout << "};" << std::endl; std::cout << "static const uint16_t " << name << "_offsets[] = {"; for (uint16_t i : offsets) { std::cout << (int) i << ","; } std::cout << "};" << std::endl; //std::cout << "out size: " << w << ":" << h << std::endl; std::cout << "static const FontWrap fnt_" << name << "(" << (int)w << "," << (int)h << "," << name << "_data," << name << "_offsets);" << std::endl; std::cout << "--------------------" << std::endl; } }; Result res; uint16_t curX = 0; FontBuilder(const int h) { //if ( (w%8) != 0 ) { // throw "width must be multiple of 8"; //} res.w = 1024; res.h = h; res.img = QImage(res.w, res.h, QImage::Format_Mono); QPainter p(&res.img); p.fillRect(0, 0, res.w, res.h, Qt::white); p.end(); } void addDummy() { // update res.offsets.push_back(curX); curX += 0; } void addIcon(QString file, float w, float h, int atHeight) { // //QImage img = QIcon("filepath.svg").pixmap(QSize()).toImage(); // QSvgRenderer renderer(file); // QImage img(pixelSize, pixelSize, QImage::Format_ARGB32); // //pm.fill(Qt::blue); // QPainter painter(&img); // painter.fillRect(0, 0, pixelSize, pixelSize, Qt::blue); // renderer.render(&painter, img.rect()); // // renderer // QPainter p(&res.img); // p.setRenderHint(QPainter::Antialiasing, false); // p.setRenderHint(QPainter::TextAntialiasing, false); // //p.setPen(Qt::white); // // render // p.drawImage(curX, atHeight, img); // p.end(); // renderer QPainter p(&res.img); p.setRenderHint(QPainter::Antialiasing, false); p.setRenderHint(QPainter::TextAntialiasing, false); p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setRenderHint(QPainter::HighQualityAntialiasing, false); // render the image QSvgRenderer renderer(file); //QImage img(pixelSize, pixelSize, QImage::Format_RGB888); QRect rect(curX, 0, w, h); //p.fillRect(rect, Qt::blue); renderer.render(&p, rect); // update res.offsets.push_back(curX); curX += w+1; } void addCharsMonoFromImage(QString file, const int charW, unsigned char cFirst, unsigned char cLast) { // renderer // QPainter p(&res.img); // p.setRenderHint(QPainter::Antialiasing, false); // p.setRenderHint(QPainter::TextAntialiasing, false); int stride = 1; QImage img; img.load(file); res.img = img; res.w = img.width(); res.h = img.height(); // p.drawImage(0, 0, img); // draw letters for (unsigned char c = cFirst; c < cLast; ++c) { int x1 = (c-cFirst) * (charW+stride); int w = charW; int y1 = 0; int h = res.h; QRect rect = QRect(x1, y1, w, h); res.offsets.push_back(curX); curX += std::ceil(rect.width()) + 1; } // p.end(); } void addChars(QString fontFile, float pixelSize, int atHeight, unsigned char cFirst, unsigned char cLast, std::function fixFunc = nullptr) { // renderer QPainter p(&res.img); p.setRenderHint(QPainter::Antialiasing, false); p.setRenderHint(QPainter::TextAntialiasing, false); p.setPen(Qt::black); // the font int id = QFontDatabase::addApplicationFont(fontFile); QString family = QFontDatabase::applicationFontFamilies(id).at(0); QFont fnt(family); if (pixelSize == -1) { ; } else if (pixelSize > 100) { fnt.setPointSize(pixelSize-100); } else { fnt.setPixelSize(pixelSize); } QFontMetrics fm(fnt); // enable p.setFont(fnt); // draw letters for (unsigned char c = cFirst; c < cLast; ++c) { QRect rect = fm.boundingRect(c); QString str = ""; str += c; res.offsets.push_back(curX); int drawOffsetX = 0; // apply rectangle fixing function? if (fixFunc) { fixFunc(c, rect); // hack for some chars if (rect.x() < 0) {drawOffsetX = -rect.x();} } std::cout << " " << c << " : " << rect.width() << " cur: " << curX << std::endl; p.drawText(curX+drawOffsetX, atHeight, str); curX += std::ceil(rect.width()) + 1; // 1 pixel space between chars } p.end(); } const Result& get() { // crop image (only used region) res.w = (curX/8+1)*8; res.img = res.img.copy(0,0,res.w,res.h); // convert to bitfield const unsigned int bytes = res.w/8 * res.h; res.data.resize(bytes); for (int y = 0; y < res.h; ++y) { for (int x = 0; x < res.w; ++x) { const QColor pixel = res.img.pixelColor(x,y); bool set = pixel.red() + pixel.green() + pixel.blue() == 0; if (set) { const unsigned int idx = (x/8) + (y*res.w/8); res.data[idx] |= (1 << (x%8)); } } } return res; } /* Result build(const QString& fontFile, int maxChar, float pixelSize, const int oh) { // the font int id = QFontDatabase::addApplicationFont(fontFile); QString family = QFontDatabase::applicationFontFamilies(id).at(0); QFont fnt(family); fnt.setPixelSize(pixelSize); QFontMetrics fm(fnt); // first chars are unused std::vector offsets; for (unsigned char c = 0; c <= 32; ++c) { offsets.push_back(0); } // estimate total width and remember character offsets int mx = 0; for (unsigned char c = 32; c < maxChar; ++c) { QRect rect = fm.boundingRect(c); mx += std::ceil(rect.width()) + 1; //if (c < 128 && rect.height() > my) {my = rect.height();} offsets.push_back(mx); } // width/height int w = mx; int h = oh; // width/height next multiple of 8 int ow = ((w-1)/8+1)*8; //int oh = h; QImage img = QImage(ow, oh, QImage::Format_RGB888); QPainter p(&img); p.setRenderHint(QPainter::Antialiasing, false); p.setRenderHint(QPainter::TextAntialiasing, false); p.setPen(Qt::white); p.setFont(fnt); p.fillRect(0, 0, w, h, Qt::black); // draw image std::vector data; for (unsigned char c = 32; c < maxChar; ++c) { QRect rect = fm.boundingRect(c); QString str = ""; str += c; int x = offsets[c]; p.drawText(x, h, str); } p.end(); // convert to bitfield const unsigned int bytes = ow/8 * oh; data.resize(bytes); for (int y = 0; y < oh; ++y) { for (int x = 0; x < ow; ++x) { bool set = img.pixelColor(x,y).red() > 128; if (set) { const unsigned int idx = (x/8) + (y*ow/8); data[idx] |= (1 << (x%8)); } } } // remove initial empty offsets offsets.erase(offsets.begin(), offsets.begin()+32); //img.save("/tmp/1.png"); //int i = 0; (void) i; Result res; res.data = data; res.offsets = offsets; res.w = ow; res.h = oh; res.img = img; return res; } */ }; #endif // FONTBUILDER_H