Created
December 13, 2020 12:07
-
-
Save dan-oak/0c0d518d4304d0b8bbdfeff3481bec9a to your computer and use it in GitHub Desktop.
Usage example of stb_truetype.h in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <string> | |
#include <fstream> | |
#include <stb/image_write.hpp> | |
#include <stb/truetype.hpp> | |
#include <cmath> | |
#include <map> | |
#include <fmt/core.h> | |
const std::string dir = "."; | |
typedef unsigned char byte; | |
typedef std::vector<byte> buffer; | |
buffer read_file (const std::string &filename) { | |
std::ifstream file(filename, std::ios::binary); | |
return buffer( | |
std::istreambuf_iterator<char>(file), | |
std::istreambuf_iterator<char>() | |
); | |
} | |
void make_rgba_from_single_channel (buffer &data) { | |
auto src_sz = data.size(); | |
auto dst_sz = src_sz * 4; | |
data.resize(dst_sz); | |
byte *src, *dst; | |
for (src = &data[src_sz - 1], dst = &data[dst_sz - 4]; dst >= &data[0]; src--, dst -= 4) { | |
dst[0] = dst[1] = dst[2] = (*src > 0) ? 255 : 0; | |
dst[3] = *src; | |
} | |
} | |
struct pos { | |
int x; | |
int y; | |
}; | |
struct box { | |
pos a; | |
pos b; | |
}; | |
template <> | |
struct fmt::formatter<pos> { | |
char presentation = 'f'; | |
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } | |
template <typename FormatContext> | |
auto format(const pos& p, FormatContext& ctx) { | |
return fmt::format_to(ctx.out(), "[{},{}]", p.x, p.y); | |
} | |
}; | |
int main () { | |
char c = 'g'; | |
fmt::print("character = {}\n", c); | |
buffer font_buf = read_file(dir + "/nasalization-rg.ttf"); | |
stbtt_fontinfo font_info; { | |
if (!stbtt_InitFont(&font_info, font_buf.data(), 0)) | |
fmt::print("Failed to load font\n"); | |
} | |
int pixel_height = 32; | |
float scalar = stbtt_ScaleForPixelHeight(&font_info, pixel_height); | |
fmt::print("scalar = {}\n", scalar); | |
auto scale = [scalar](int i) { | |
return int(roundf((float)i * scalar)); | |
}; | |
int ascent, descent, line_gap; { | |
int ascenti, descenti, line_gapi; | |
stbtt_GetFontVMetrics(&font_info, &ascenti, &descenti, &line_gapi); | |
ascent = scale(ascenti); | |
descent = scale(descenti); | |
line_gap = scale(line_gapi); | |
} | |
fmt::print("ascent = {}\n", ascent); | |
fmt::print("descent = {}\n", descent); | |
fmt::print("line_gap = {}\n", line_gap); | |
int adv_x; | |
int l_bearing; { | |
int adv_xi; | |
int l_bearingi; | |
stbtt_GetCodepointHMetrics(&font_info, c, &adv_xi, &l_bearingi); | |
adv_x = scale(adv_xi); | |
l_bearing = scale(l_bearingi); | |
} | |
fmt::print("adv_x = {}\n", adv_x); | |
fmt::print("l_bearing = {}\n", l_bearing); | |
pos size; { | |
size.x = adv_x; | |
size.y = ascent - descent; | |
} | |
fmt::print("size = {}\n", size); | |
box bb; { | |
stbtt_GetCodepointBitmapBox(&font_info, c, scalar, scalar, | |
&bb.a.x, &bb.a.y, &bb.b.x, &bb.b.y); | |
} | |
fmt::print("bb.a = {}\n", bb.a); | |
fmt::print("bb.b = {}\n", bb.b); | |
pos b_size = { | |
.x = bb.b.x - bb.a.x, | |
.y = bb.b.y - bb.a.y, | |
}; | |
fmt::print("b_size = {}\n", b_size); | |
int y = ascent + bb.a.y; | |
fmt::print("y = {}\n", y); | |
buffer bitmap(size.x * size.y); | |
int bitmap_offset = y*size.x + l_bearing; | |
byte *output = bitmap.data() + bitmap_offset; | |
stbtt_MakeCodepointBitmap(&font_info, output, b_size.x, b_size.y, | |
size.x, scalar, scalar, c); | |
for (int i = 0; i < size.y; ++i) { | |
for (int j = 0; j < size.x; ++j) | |
std::cout << " .:ioVM@"[bitmap[i*size.x + j]>>5]; | |
std::cout << "\n"; | |
} | |
stbi_write_png((dir+"/out/glyph.png").c_str(), | |
size.x, size.y, 1, bitmap.data(), size.x); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment