#include #include #include #include #include #include #include static unsigned char clamp_channel(float v) { if (v <= 0.0f) return 0; if (v >= 1.0f) return 255; return static_cast(std::lround(v * 255.0f)); } int main(int argc, char **argv) { if (argc < 3) { std::fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } const char *fontPath = argv[1]; unsigned codepoint = std::strtoul(argv[2], nullptr, 0); auto *ft = msdfgen::initializeFreetype(); if (!ft) return 1; auto *font = msdfgen::loadFont(ft, fontPath); if (!font) return 1; msdfgen::Shape shape; double advance = 0.0; if (!msdfgen::loadGlyph(shape, font, msdfgen::GlyphIndex(codepoint), msdfgen::FONT_SCALING_EM_NORMALIZED, &advance)) { std::fprintf(stderr, "Failed to load glyph %u\n", codepoint); return 1; } shape.normalize(); msdfgen::edgeColoringSimple(shape, 3.0); auto bounds = shape.getBounds(); double emScale = 48.0; double pxRange = 4.0; int bmp_w = std::max(1, (int)std::ceil((bounds.r - bounds.l) * emScale + 2.0 * pxRange)); int bmp_h = std::max(1, (int)std::ceil((bounds.t - bounds.b) * emScale + 2.0 * pxRange)); msdfgen::Bitmap bitmap(bmp_w, bmp_h); msdfgen::Vector2 scale(emScale, emScale); msdfgen::Vector2 translate(-bounds.l * emScale + pxRange, -bounds.b * emScale + pxRange); msdfgen::generateMSDF(bitmap, shape, pxRange, scale, translate); std::vector buffer(static_cast(bmp_w) * bmp_h * 4); for (int y = 0; y < bmp_h; ++y) { int dst_y = bmp_h - 1 - y; for (int x = 0; x < bmp_w; ++x) { const float *px = bitmap(x, y); size_t idx = (static_cast(dst_y) * bmp_w + x) * 4; buffer[idx + 0] = clamp_channel(px[0]); buffer[idx + 1] = clamp_channel(px[1]); buffer[idx + 2] = clamp_channel(px[2]); buffer[idx + 3] = 255; } } int minX = bmp_w, minY = bmp_h, maxX = -1, maxY = -1; for (int y = 0; y < bmp_h; ++y) { for (int x = 0; x < bmp_w; ++x) { size_t idx = (static_cast(y) * bmp_w + x) * 4; unsigned char r = buffer[idx]; unsigned char g = buffer[idx + 1]; unsigned char b = buffer[idx + 2]; bool interesting = !(r == 0 && g == 0 && b == 0) && !(r == 255 && g == 255 && b == 255); if (interesting) { if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; } } } std::printf("bmp %dx%d\n", bmp_w, bmp_h); if (maxX >= minX && maxY >= minY) { std::printf("interesting bbox: x=[%d,%d] y=[%d,%d]\n", minX, maxX, minY, maxY); } msdfgen::destroyFont(font); msdfgen::deinitializeFreetype(ft); return 0; }