diff options
Diffstat (limited to 'tools/mcufontencoder/src/exporttools.cc')
-rw-r--r-- | tools/mcufontencoder/src/exporttools.cc | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/tools/mcufontencoder/src/exporttools.cc b/tools/mcufontencoder/src/exporttools.cc new file mode 100644 index 00000000..b58ee8ec --- /dev/null +++ b/tools/mcufontencoder/src/exporttools.cc @@ -0,0 +1,179 @@ +#include "exporttools.hh" +#include <iomanip> +#include <set> + +namespace mcufont { + + +// Convert a file name to a valid C identifier +std::string filename_to_identifier(std::string name) +{ + // If the name contains path separators (/ or \), take only the last part. + size_t pos = name.find_last_of("/\\"); + if (pos != std::string::npos) + name = name.substr(pos + 1); + + // If the name contains a file extension, strip it. + pos = name.find_first_of("."); + if (pos != std::string::npos) + name = name.substr(0, pos); + + // Replace any special characters with _. + for (pos = 0; pos < name.size(); pos++) + { + if (!isalnum(name.at(pos))) + name.at(pos) = '_'; + } + + return name; +} + +// Write a vector of integers as line-wrapped hex/integer data for initializing const array. +void wordwrap_vector(std::ostream &out, const std::vector<unsigned> &data, + const std::string &prefix, size_t width) +{ + int values_per_column = (width <= 2) ? 16 : 8; + + std::ios::fmtflags flags(out.flags()); + out << prefix; + out << std::hex << std::setfill('0'); + for (size_t i = 0; i < data.size(); i++) + { + if (i % values_per_column == 0 && i != 0) + out << std::endl << prefix; + + out << "0x" << std::setw(width) << (int)data.at(i) << ", "; + } + out.flags(flags); +} + +// Write a vector of integers as a C constant array of given datatype. + void write_const_table(std::ostream &out, const std::vector<unsigned> &data, + const std::string &datatype, const std::string &tablename, + size_t width) +{ + out << "static const " << datatype << " " << tablename; + out << "[" << data.size() << "] = {" << std::endl; + wordwrap_vector(out, data, " ", width); + out << std::endl << "};" << std::endl; + out << std::endl; +} + +int get_min_x_advance(const DataFile &datafile) +{ + int min = datafile.GetGlyphEntry(0).width; + + for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable()) + { + if (min > g.width) + min = g.width; + } + + return min; +} + +int get_max_x_advance(const DataFile &datafile) +{ + int max = 0; + + for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable()) + { + if (max < g.width) + max = g.width; + } + + return max; +} + +// Select the character to use as a fallback. +int select_fallback_char(const DataFile &datafile) +{ + std::set<int> chars; + + size_t i = 0; + for (const DataFile::glyphentry_t &g: datafile.GetGlyphTable()) + { + for (size_t c: g.chars) + { + chars.insert(c); + } + i++; + } + + if (chars.count(0xFFFD)) + return 0xFFFD; // Unicode replacement character + + if (chars.count(0)) + return 0; // Used by many BDF fonts as replacement char + + if (chars.count('?')) + return '?'; + + return ' '; +} + +// Decide how to best divide the characters in the font into ranges. +// Limitations are: +// - Gaps longer than minimum_gap should result in separate ranges. +// - Each range can have encoded data size of at most maximum_size. +std::vector<char_range_t> compute_char_ranges(const DataFile &datafile, + std::function<size_t(size_t)> get_encoded_glyph_size, + size_t maximum_size, + size_t minimum_gap) +{ + std::vector<char_range_t> result; + std::map<size_t, size_t> char_to_glyph = datafile.GetCharToGlyphMap(); + std::vector<size_t> chars; + + // Get list of all characters in numeric order. + for (auto iter : char_to_glyph) + chars.push_back(iter.first); + + // Pick out ranges until we have processed all characters + size_t i = 0; + while (i < chars.size()) + { + char_range_t range; + range.first_char = chars.at(i); + + // Find the point where there is a gap larger than minimum_gap. + i++; + while (i < chars.size() && chars.at(i) - chars.at(i - 1) < minimum_gap) + i++; + + uint16_t last_char = chars.at(i - 1); + + // Then store the indices of glyphs for each character + size_t data_length = 0; + for (size_t j = range.first_char; j <= last_char; j++) + { + if (char_to_glyph.count(j) == 0) + { + // Missing character + range.glyph_indices.push_back(-1); + continue; + } + + int glyph_index = char_to_glyph[j]; + + // Monitor the amount of the data in the range and split it + // if it grows too large. + data_length += get_encoded_glyph_size(glyph_index); + if (data_length > maximum_size) + { + last_char = j - 1; + break; + } + + range.glyph_indices.push_back(glyph_index); + } + + range.char_count = last_char - range.first_char + 1; + result.push_back(range); + } + + return result; +} + + +} |