Rought font extractor that probably has a memory error causing it to behave mysteriously, and the designer now uses a json file of the characters that will work.
This commit is contained in:
parent
9ab064126f
commit
a9e25668fb
7 changed files with 293 additions and 44 deletions
|
@ -3,7 +3,7 @@
|
||||||
"WALL_TILE": "\ua5b8",
|
"WALL_TILE": "\ua5b8",
|
||||||
"FLOOR_TILE": "\u2849",
|
"FLOOR_TILE": "\u2849",
|
||||||
"PLAYER_TILE": "\ua66b",
|
"PLAYER_TILE": "\ua66b",
|
||||||
"ENEMY_TILE": "Ω",
|
"ENEMY_TILE": "\u1d5c",
|
||||||
"BG_TILE": "█",
|
"BG_TILE": "█",
|
||||||
"WATER_TILE": "\u26c6"
|
"WATER_TILE": "\u26c6"
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,3 +17,4 @@ const int MAX_FONT_SIZE = 140;
|
||||||
const int MIN_FONT_SIZE = 20;
|
const int MIN_FONT_SIZE = 20;
|
||||||
const int SCREEN_WIDTH = 40;
|
const int SCREEN_WIDTH = 40;
|
||||||
const int SCREEN_HEIGHT = 30;
|
const int SCREEN_HEIGHT = 30;
|
||||||
|
#define FONT_FILE_NAME "./assets/text.otf"
|
||||||
|
|
|
@ -92,6 +92,14 @@ designer = executable('designer', [
|
||||||
],
|
],
|
||||||
dependencies: dependencies)
|
dependencies: dependencies)
|
||||||
|
|
||||||
|
fontextract = executable('fontextract', [
|
||||||
|
'dbc.cpp',
|
||||||
|
'rand.cpp',
|
||||||
|
'config.cpp',
|
||||||
|
'tools/fontextract.cpp'
|
||||||
|
],
|
||||||
|
dependencies: dependencies)
|
||||||
|
|
||||||
img2ansi = executable('img2ansi', [
|
img2ansi = executable('img2ansi', [
|
||||||
'dbc.cpp',
|
'dbc.cpp',
|
||||||
'panel.cpp',
|
'panel.cpp',
|
||||||
|
|
|
@ -25,7 +25,7 @@ SFMLRender::SFMLRender() :
|
||||||
$ansi($default_fg, $default_bg)
|
$ansi($default_fg, $default_bg)
|
||||||
{
|
{
|
||||||
// force true color, but maybe I want to support different color sets
|
// force true color, but maybe I want to support different color sets
|
||||||
$font.loadFromFile("./assets/text.otf");
|
$font.loadFromFile(FONT_FILE_NAME);
|
||||||
$font.setSmooth(false);
|
$font.setSmooth(false);
|
||||||
$ui_text.setFont($font);
|
$ui_text.setFont($font);
|
||||||
$ui_text.setPosition(0,0);
|
$ui_text.setPosition(0,0);
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
TODAY'S GOAL:
|
TODAY'S GOAL:
|
||||||
|
|
||||||
|
====
|
||||||
|
Font Extractor
|
||||||
|
===
|
||||||
|
|
||||||
1. Why do Sliders only have to be kept around forever and can't go in containers like everything else?
|
1. Why do Sliders only have to be kept around forever and can't go in containers like everything else?
|
||||||
2. Why are sliders not selected when I click on them? Is it a hover?
|
2. Why are sliders not selected when I click on them? Is it a hover?
|
||||||
3. Why do fonts render blank? Also when I scroll they slowly disappear until there's a column.
|
3. Why do fonts render blank? Also when I scroll they slowly disappear until there's a column.
|
||||||
4. Use freetype to iterate chars.
|
* \u2738 is missing on the row when in grid but works when clicked.
|
||||||
5. Why are all wchar converted chars in from_unicode 3 bytes not 2?
|
|
||||||
|
|
||||||
* A designer tool to help find characters for foreground, background, and figure out their colors.
|
* A designer tool to help find characters for foreground, background, and figure out their colors.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
#include <chrono> // for operator""s, chrono_literals
|
#include <chrono> // for operator""s, chrono_literals
|
||||||
#include <thread> // for sleep_for
|
#include <thread> // for sleep_for
|
||||||
#include "dinkyecs.hpp"
|
#include "dinkyecs.hpp"
|
||||||
|
@ -13,9 +15,9 @@
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ft2build.h>
|
#include <nlohmann/json.hpp>
|
||||||
#include FT_FREETYPE_H
|
|
||||||
|
|
||||||
|
using namespace nlohmann;
|
||||||
using namespace fmt;
|
using namespace fmt;
|
||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
@ -26,58 +28,80 @@ using std::string, std::wstring, std::vector;
|
||||||
const Point GRID_SIZE={15,8};
|
const Point GRID_SIZE={15,8};
|
||||||
const int DEFAULT_FONT_SIZE=200;
|
const int DEFAULT_FONT_SIZE=200;
|
||||||
|
|
||||||
|
struct FontGridCell {
|
||||||
|
size_t cm_index;
|
||||||
|
string as_string;
|
||||||
|
wstring as_wstring;
|
||||||
|
};
|
||||||
|
|
||||||
struct FontGrid {
|
struct FontGrid {
|
||||||
size_t width;
|
size_t width;
|
||||||
size_t height;
|
size_t height;
|
||||||
vector<vector<string>> $chars;
|
vector<vector<FontGridCell>> $grid;
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
|
||||||
|
vector<wstring> $wcharmap;
|
||||||
|
vector<string> $charmap;
|
||||||
|
|
||||||
FontGrid(size_t width, size_t height) :
|
FontGrid(size_t width, size_t height) :
|
||||||
width(width), height(height),
|
width(width), height(height),
|
||||||
$chars(height, vector<string>(width, ""))
|
$grid(height, vector<FontGridCell>(width, {0, "", L""}))
|
||||||
{
|
{
|
||||||
|
configure_font();
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(wchar_t start_char, bool fill) {
|
void configure_font() {
|
||||||
wchar_t cur_char = start_char;
|
std::ifstream in_file("./fontlist.json");
|
||||||
|
json input = json::parse(in_file);
|
||||||
|
|
||||||
|
for(auto inchar : input) {
|
||||||
|
$charmap.push_back(inchar);
|
||||||
|
$wcharmap.push_back($converter.from_bytes(inchar));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t max_chars() {
|
||||||
|
return $wcharmap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(size_t start_char, bool fill) {
|
||||||
|
size_t next_char = start_char;
|
||||||
|
|
||||||
for(size_t y = 0; y < height; ++y) {
|
for(size_t y = 0; y < height; ++y) {
|
||||||
for(size_t x = 0; x < width; ++x) {
|
for(size_t x = 0; x < width; ++x) {
|
||||||
if(!fill) {
|
if(!fill) {
|
||||||
cur_char += (x+1) * (y+1);
|
next_char++;
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring out_w{cur_char};
|
$grid[y][x] = {
|
||||||
$chars[y][x] = from_unicode(out_w);
|
.cm_index = next_char,
|
||||||
|
.as_string = $charmap[next_char],
|
||||||
|
.as_wstring = $wcharmap[next_char]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string from_unicode(wstring input) {
|
size_t charmap_index(size_t x, size_t y) {
|
||||||
try {
|
FontGridCell &cell = $grid[y][x];
|
||||||
return $converter.to_bytes(input);
|
return cell.cm_index;
|
||||||
} catch(...) {
|
|
||||||
return $converter.to_bytes(L"?");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t to_unicode_char(size_t x, size_t y) {
|
string& as_string(size_t x, size_t y) {
|
||||||
try {
|
return $grid[y][x].as_string;
|
||||||
string input = $chars[y][x]; // BUG: bounds check this instead
|
|
||||||
return $converter.from_bytes(input)[0];
|
|
||||||
} catch(...) {
|
|
||||||
return L'?';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string at(size_t x, size_t y) {
|
wstring& as_wstring(size_t x, size_t y) {
|
||||||
return $chars[y][x];
|
return $grid[y][x].as_wstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wchar_t as_wchar(size_t cm_index) {
|
||||||
|
return $wcharmap[cm_index][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int page_size() {
|
unsigned int page_size() {
|
||||||
return width * height;
|
return width * height;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WhatTheColor {
|
struct WhatTheColor {
|
||||||
|
@ -97,8 +121,8 @@ class GUI {
|
||||||
Canvas $canvas;
|
Canvas $canvas;
|
||||||
SFMLRender $renderer;
|
SFMLRender $renderer;
|
||||||
FontGrid $font_grid;
|
FontGrid $font_grid;
|
||||||
wchar_t $start_char = L'\u28cc';
|
size_t $start_char = 0;
|
||||||
wchar_t $fill_char = WCHAR_MIN;
|
size_t $fill_char = 0;
|
||||||
WhatTheColor $fg_color;
|
WhatTheColor $fg_color;
|
||||||
WhatTheColor $bg_color;
|
WhatTheColor $bg_color;
|
||||||
Component $fg_settings;
|
Component $fg_settings;
|
||||||
|
@ -113,7 +137,11 @@ class GUI {
|
||||||
$bg_color{.h=100, .s=100, .v=100}
|
$bg_color{.h=100, .s=100, .v=100}
|
||||||
{
|
{
|
||||||
resize_fonts(DEFAULT_FONT_SIZE);
|
resize_fonts(DEFAULT_FONT_SIZE);
|
||||||
$font_grid.render($start_char, false);
|
render_grid($start_char, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_grid(size_t start_char, bool fill) {
|
||||||
|
$font_grid.render(start_char, fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize_fonts(int new_size) {
|
void resize_fonts(int new_size) {
|
||||||
|
@ -124,11 +152,12 @@ class GUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_font_grid() {
|
void draw_font_grid() {
|
||||||
|
int flip_it = 0;
|
||||||
for(size_t y = 0; y < $font_grid.height; y++) {
|
for(size_t y = 0; y < $font_grid.height; y++) {
|
||||||
for(size_t x = 0; x < $font_grid.width; x++) {
|
for(size_t x = 0; x < $font_grid.width; x++, flip_it++) {
|
||||||
$canvas.DrawText(x * 2, y * 4, $font_grid.at(x, y), [&](auto &pixel) {
|
$canvas.DrawText(x * 2, y * 4, $font_grid.as_string(x, y), [&](auto &pixel) {
|
||||||
pixel.foreground_color = Color::HSV($fg_color.h, $fg_color.s, $fg_color.v);
|
pixel.foreground_color = Color::HSV($fg_color.h, $fg_color.s, $fg_color.v);
|
||||||
pixel.background_color = Color::HSV($bg_color.h, $bg_color.s, $bg_color.v);
|
pixel.background_color = Color::HSV($bg_color.h, $bg_color.s, $bg_color.v / (flip_it % 2 * 2 + 1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,10 +179,12 @@ class GUI {
|
||||||
$bg_color.v_slider = Slider("BG V:", &$bg_color.v, 0, 255, 1);
|
$bg_color.v_slider = Slider("BG V:", &$bg_color.v, 0, 255, 1);
|
||||||
|
|
||||||
$status_ui.set_renderer(Renderer([&]{
|
$status_ui.set_renderer(Renderer([&]{
|
||||||
|
wchar_t fill_char = $font_grid.as_wchar($fill_char);
|
||||||
|
|
||||||
return hbox({
|
return hbox({
|
||||||
hflow(
|
hflow(
|
||||||
vbox(
|
vbox(
|
||||||
text(format("\\u{:x} {} MIN: {}, MAX: {}", int($fill_char), int($fill_char), WCHAR_MIN, WCHAR_MAX)) | border,
|
text(format("\\u{:x} {} IDX: {}, MIN: {}, MAX: {}", int(fill_char), int(fill_char), $fill_char, WCHAR_MIN, WCHAR_MAX)) | border,
|
||||||
separator(),
|
separator(),
|
||||||
text(format("FG H: {}, S: {}, V: {}",
|
text(format("FG H: {}, S: {}, V: {}",
|
||||||
$fg_color.h, $fg_color.s, $fg_color.v)) | border,
|
$fg_color.h, $fg_color.s, $fg_color.v)) | border,
|
||||||
|
@ -190,12 +221,12 @@ class GUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
void select_cell(Point pos) {
|
void select_cell(Point pos) {
|
||||||
$fill_char = $font_grid.to_unicode_char(pos.x, pos.y);
|
$fill_char = $font_grid.charmap_index(pos.x, pos.y);
|
||||||
$font_grid.render($fill_char, true);
|
render_grid($fill_char, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deselect_cell() {
|
void deselect_cell() {
|
||||||
$font_grid.render($start_char, false);
|
render_grid($start_char, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle_ui_events() {
|
bool handle_ui_events() {
|
||||||
|
@ -210,13 +241,13 @@ class GUI {
|
||||||
return true;
|
return true;
|
||||||
} else if(event.type == sf::Event::KeyPressed) {
|
} else if(event.type == sf::Event::KeyPressed) {
|
||||||
if(KB::isKeyPressed(KB::Up)) {
|
if(KB::isKeyPressed(KB::Up)) {
|
||||||
$start_char = std::max(WCHAR_MIN+1, $start_char - $font_grid.page_size());
|
$start_char = std::max(size_t(1), $start_char - $font_grid.page_size());
|
||||||
$font_grid.render($start_char, false);
|
render_grid($start_char, false);
|
||||||
event_happened = true;
|
event_happened = true;
|
||||||
$renderer.clear_cache();
|
$renderer.clear_cache();
|
||||||
} else if(KB::isKeyPressed(KB::Down)) {
|
} else if(KB::isKeyPressed(KB::Down)) {
|
||||||
$start_char = std::min(WCHAR_MAX, $start_char + $font_grid.page_size());
|
$start_char = std::min($font_grid.max_chars(), $start_char + $font_grid.page_size());
|
||||||
$font_grid.render($start_char, false);
|
render_grid($start_char, false);
|
||||||
$renderer.clear_cache();
|
$renderer.clear_cache();
|
||||||
} else if(KB::isKeyPressed(KB::Equal)) {
|
} else if(KB::isKeyPressed(KB::Equal)) {
|
||||||
resize_fonts(font_size + 10);
|
resize_fonts(font_size + 10);
|
||||||
|
@ -264,7 +295,6 @@ int main(int argc, char *argv[]) {
|
||||||
gui.render_scene();
|
gui.render_scene();
|
||||||
|
|
||||||
if(gui.handle_ui_events()) {
|
if(gui.handle_ui_events()) {
|
||||||
println("THERE WERE EVENTS");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(10ms);
|
std::this_thread::sleep_for(10ms);
|
||||||
|
|
207
tools/fontextract.cpp
Normal file
207
tools/fontextract.cpp
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono> // for operator""s, chrono_literals
|
||||||
|
#include <thread> // for sleep_for
|
||||||
|
#include "dbc.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <vector>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include <SFML/Graphics/Font.hpp>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_TRUETYPE_TABLES_H
|
||||||
|
#include FT_TRUETYPE_IDS_H
|
||||||
|
|
||||||
|
using namespace nlohmann;
|
||||||
|
using namespace fmt;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using std::string, std::wstring, std::vector;
|
||||||
|
|
||||||
|
const size_t CLEAR_CACHE_POINT=100;
|
||||||
|
|
||||||
|
struct FontIndex {
|
||||||
|
size_t cm_index; // charmap index
|
||||||
|
string glyph;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FontExtractor {
|
||||||
|
size_t $clear_count = 1;
|
||||||
|
wchar_t ui_base_char = L'█';
|
||||||
|
vector<FontIndex> $index;
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
|
||||||
|
vector<string> $charmap;
|
||||||
|
vector<wchar_t> $wcharmap;
|
||||||
|
sf::Font $font;
|
||||||
|
sf::FloatRect $grid_bounds;
|
||||||
|
int $font_size;
|
||||||
|
fs::path $font_path;
|
||||||
|
json $results;
|
||||||
|
|
||||||
|
FontExtractor(fs::path font_path) :
|
||||||
|
$font_path(font_path)
|
||||||
|
{
|
||||||
|
bool good = $font.loadFromFile($font_path.string());
|
||||||
|
dbc::check(good, format("failed to load font {}", $font_path.string()));
|
||||||
|
$font.setSmooth(false);
|
||||||
|
|
||||||
|
for(int i = 100; i < 200; i++) {
|
||||||
|
auto glyph = $font.getGlyph(ui_base_char, i, false);
|
||||||
|
if(glyph.bounds.width > 0 && glyph.bounds.height > 0) {
|
||||||
|
$grid_bounds = glyph.bounds;
|
||||||
|
$font_size = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbc::check($grid_bounds.width > 0 && $grid_bounds.height > 0, "couldn't find a valid font size");
|
||||||
|
|
||||||
|
println("!!!!!!!!!!!!!!!!!!!!! FONT SIZE {}", $font_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void configure_font() {
|
||||||
|
FT_ULong charcode;
|
||||||
|
FT_UInt gindex;
|
||||||
|
FT_String buf[32] = {0};
|
||||||
|
FT_Library library;
|
||||||
|
FT_Face face;
|
||||||
|
|
||||||
|
auto error = FT_Init_FreeType(&library);
|
||||||
|
dbc::check(!error, "Failed to initialize freetype library.");
|
||||||
|
|
||||||
|
error = FT_New_Face(library, FONT_FILE_NAME, 0, &face);
|
||||||
|
|
||||||
|
dbc::check(face->num_faces == 1, format("Font {} has {} but I only support 1.", FONT_FILE_NAME, face->num_faces));
|
||||||
|
dbc::check(face->charmap, "Font doesn't have a charmap.");
|
||||||
|
|
||||||
|
println("Font charmaps {}", face->num_charmaps);
|
||||||
|
auto active = FT_Get_Charmap_Index(face->charmap);
|
||||||
|
|
||||||
|
for(int i = 0; i < face->num_charmaps; i++) {
|
||||||
|
auto format = FT_Get_CMap_Format(face->charmaps[i]);
|
||||||
|
auto lang_id = FT_Get_CMap_Language_ID(face->charmaps[i]);
|
||||||
|
|
||||||
|
println("{}: {} {}, active: {}, platform: {}, encoding: {}, ms_unicode: {}, language: {}",
|
||||||
|
i,
|
||||||
|
format >= 0 ? "format" : "synthetic",
|
||||||
|
format,
|
||||||
|
i == active,
|
||||||
|
face->charmaps[i]->platform_id,
|
||||||
|
face->charmaps[i]->encoding_id,
|
||||||
|
TT_MS_ID_UNICODE_CS,
|
||||||
|
lang_id);
|
||||||
|
|
||||||
|
// BUG: this is windows only
|
||||||
|
if(face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS) {
|
||||||
|
FT_Set_Charmap(face, face->charmaps[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_names = FT_HAS_GLYPH_NAMES(face);
|
||||||
|
|
||||||
|
// get the first char of the map
|
||||||
|
charcode = FT_Get_First_Char(face, &gindex);
|
||||||
|
|
||||||
|
// go through every char and pre-convert
|
||||||
|
for(int i = 0; gindex; i++) {
|
||||||
|
if(has_names) FT_Get_Glyph_Name(face, gindex, buf, 32 );
|
||||||
|
|
||||||
|
// store it in my pre-convert charmap for later
|
||||||
|
wstring wcodestr{(wchar_t)charcode};
|
||||||
|
string codestr = from_unicode(wcodestr);
|
||||||
|
$charmap.emplace_back(codestr);
|
||||||
|
$wcharmap.push_back(charcode);
|
||||||
|
|
||||||
|
// keep going
|
||||||
|
charcode = FT_Get_Next_Char(face, charcode, &gindex );
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Done_Face(face);
|
||||||
|
FT_Done_FreeType(library);
|
||||||
|
|
||||||
|
println("FreeType extracted {} glyphs.", $charmap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t next_valid_char(size_t cur_char) {
|
||||||
|
for(size_t i = cur_char+1; i < $wcharmap.size(); i++) {
|
||||||
|
wchar_t test_char = $wcharmap[i];
|
||||||
|
if($font.hasGlyph(test_char)) {
|
||||||
|
auto glyph = $font.getGlyph(test_char, $font_size, false);
|
||||||
|
auto bounds = glyph.bounds;
|
||||||
|
|
||||||
|
// skip bad chars
|
||||||
|
if(bounds.width <= 0 || bounds.height <= 0) continue;
|
||||||
|
|
||||||
|
if(bounds.width <= $grid_bounds.width &&
|
||||||
|
bounds.height <= $grid_bounds.height) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_font_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void extract_valid() {
|
||||||
|
size_t cur_char = next_valid_char(1);
|
||||||
|
|
||||||
|
while(cur_char != 0) {
|
||||||
|
string out = from_unicode(wstring_at(cur_char));
|
||||||
|
$results.push_back(out);
|
||||||
|
cur_char = next_valid_char(cur_char + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string from_unicode(wstring input) {
|
||||||
|
try {
|
||||||
|
return $converter.to_bytes(input);
|
||||||
|
} catch(...) {
|
||||||
|
return $converter.to_bytes(L"?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string at(size_t x) {
|
||||||
|
return $index[x].glyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring wstring_at(size_t cm_index) {
|
||||||
|
return wstring{$wcharmap[cm_index]};
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_font_cache() {
|
||||||
|
if($clear_count % CLEAR_CACHE_POINT == 0) {
|
||||||
|
bool good = $font.loadFromFile($font_path.string());
|
||||||
|
dbc::check(good, format("failed to load font {}", $font_path.string()));
|
||||||
|
$font.setSmooth(false);
|
||||||
|
|
||||||
|
$clear_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if(argc != 3) {
|
||||||
|
println("USAGE: fontextractor <input> <output>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path font_path = argv[1];
|
||||||
|
fs::path out_path = argv[2];
|
||||||
|
|
||||||
|
dbc::check(fs::exists(font_path), "ERROR: input file doesn't exist");
|
||||||
|
|
||||||
|
FontExtractor fex(font_path);
|
||||||
|
fex.configure_font();
|
||||||
|
fex.extract_valid();
|
||||||
|
|
||||||
|
std::ofstream json_out(out_path, std::ios::binary);
|
||||||
|
json_out << fex.$results.dump(2) << std::endl;
|
||||||
|
|
||||||
|
println("Wrote {} chars to {}.", fex.$results.size(), out_path.string());
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue