aboutsummaryrefslogtreecommitdiffstats
path: root/tools/mcufontencoder/src/exporttools.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mcufontencoder/src/exporttools.cc')
-rw-r--r--tools/mcufontencoder/src/exporttools.cc179
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;
+}
+
+
+}