version 2.8
exporttools.cc
1 #include "exporttools.hh"
2 #include <iomanip>
3 #include <set>
4 
5 namespace mcufont {
6 
7 
8 // Convert a file name to a valid C identifier
9 std::string filename_to_identifier(std::string name)
10 {
11  // If the name contains path separators (/ or \), take only the last part.
12  size_t pos = name.find_last_of("/\\");
13  if (pos != std::string::npos)
14  name = name.substr(pos + 1);
15 
16  // If the name contains a file extension, strip it.
17  pos = name.find_first_of(".");
18  if (pos != std::string::npos)
19  name = name.substr(0, pos);
20 
21  // Replace any special characters with _.
22  for (pos = 0; pos < name.size(); pos++)
23  {
24  if (!isalnum(name.at(pos)))
25  name.at(pos) = '_';
26  }
27 
28  return name;
29 }
30 
31 // Write a vector of integers as line-wrapped hex/integer data for initializing const array.
32 void wordwrap_vector(std::ostream &out, const std::vector<unsigned> &data,
33  const std::string &prefix, size_t width)
34 {
35  int values_per_column = (width <= 2) ? 16 : 8;
36 
37  std::ios::fmtflags flags(out.flags());
38  out << prefix;
39  out << std::hex << std::setfill('0');
40  for (size_t i = 0; i < data.size(); i++)
41  {
42  if (i % values_per_column == 0 && i != 0)
43  out << std::endl << prefix;
44 
45  out << "0x" << std::setw(width) << (int)data.at(i) << ", ";
46  }
47  out.flags(flags);
48 }
49 
50 // Write a vector of integers as a C constant array of given datatype.
51  void write_const_table(std::ostream &out, const std::vector<unsigned> &data,
52  const std::string &datatype, const std::string &tablename,
53  size_t width)
54 {
55  out << "static const " << datatype << " " << tablename;
56  out << "[" << data.size() << "] = {" << std::endl;
57  wordwrap_vector(out, data, " ", width);
58  out << std::endl << "};" << std::endl;
59  out << std::endl;
60 }
61 
62 int get_min_x_advance(const DataFile &datafile)
63 {
64  int min = datafile.GetGlyphEntry(0).width;
65 
66  for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable())
67  {
68  if (min > g.width)
69  min = g.width;
70  }
71 
72  return min;
73 }
74 
75 int get_max_x_advance(const DataFile &datafile)
76 {
77  int max = 0;
78 
79  for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable())
80  {
81  if (max < g.width)
82  max = g.width;
83  }
84 
85  return max;
86 }
87 
88 // Select the character to use as a fallback.
89 int select_fallback_char(const DataFile &datafile)
90 {
91  std::set<int> chars;
92 
93  size_t i = 0;
94  for (const DataFile::glyphentry_t &g: datafile.GetGlyphTable())
95  {
96  for (size_t c: g.chars)
97  {
98  chars.insert(c);
99  }
100  i++;
101  }
102 
103  if (chars.count(0xFFFD))
104  return 0xFFFD; // Unicode replacement character
105 
106  if (chars.count(0))
107  return 0; // Used by many BDF fonts as replacement char
108 
109  if (chars.count('?'))
110  return '?';
111 
112  return ' ';
113 }
114 
115 // Decide how to best divide the characters in the font into ranges.
116 // Limitations are:
117 // - Gaps longer than minimum_gap should result in separate ranges.
118 // - Each range can have encoded data size of at most maximum_size.
119 std::vector<char_range_t> compute_char_ranges(const DataFile &datafile,
120  std::function<size_t(size_t)> get_encoded_glyph_size,
121  size_t maximum_size,
122  size_t minimum_gap)
123 {
124  std::vector<char_range_t> result;
125  std::map<size_t, size_t> char_to_glyph = datafile.GetCharToGlyphMap();
126  std::vector<size_t> chars;
127 
128  // Get list of all characters in numeric order.
129  for (auto iter : char_to_glyph)
130  chars.push_back(iter.first);
131 
132  // Pick out ranges until we have processed all characters
133  size_t i = 0;
134  while (i < chars.size())
135  {
136  char_range_t range;
137  range.first_char = chars.at(i);
138 
139  // Find the point where there is a gap larger than minimum_gap.
140  i++;
141  while (i < chars.size() && chars.at(i) - chars.at(i - 1) < minimum_gap)
142  i++;
143 
144  uint16_t last_char = chars.at(i - 1);
145 
146  // Then store the indices of glyphs for each character
147  size_t data_length = 0;
148  for (size_t j = range.first_char; j <= last_char; j++)
149  {
150  if (char_to_glyph.count(j) == 0)
151  {
152  // Missing character
153  range.glyph_indices.push_back(-1);
154  continue;
155  }
156 
157  int glyph_index = char_to_glyph[j];
158 
159  // Monitor the amount of the data in the range and split it
160  // if it grows too large.
161  data_length += get_encoded_glyph_size(glyph_index);
162  if (data_length > maximum_size)
163  {
164  last_char = j - 1;
165 
166  // Return the rest of characters to be processed by next range.
167  while (chars.at(i-1) > last_char)
168  i--;
169 
170  break;
171  }
172 
173  range.glyph_indices.push_back(glyph_index);
174  }
175 
176  range.char_count = last_char - range.first_char + 1;
177  result.push_back(range);
178  }
179 
180  return result;
181 }
182 
183 
184 }