version 2.8
bdf_import.cc
1 #include "bdf_import.hh"
2 #include "importtools.hh"
3 #include <sstream>
4 #include <string>
5 #include <cctype>
6 #include <stdexcept>
7 
8 namespace mcufont {
9 
10 static std::string toupper(const std::string &input)
11 {
12  std::string result;
13  for (char c: input) result.push_back(::toupper(c));
14  return result;
15 }
16 
17 static int hextoint(char c)
18 {
19  if (c >= '0' && c <= '9') return c - '0';
20  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
21  throw std::domain_error("Hex digit not in range");
22 }
23 
24 static void parse_fontinfo(std::istream &file, DataFile::fontinfo_t &fontinfo)
25 {
26  std::string line;
27  while (std::getline(file, line))
28  {
29  std::istringstream s(line);
30  std::string tag;
31  s >> tag;
32  tag = toupper(tag);
33 
34  if (tag == "FONT")
35  {
36  while (isspace(s.peek())) s.get();
37  std::getline(s, fontinfo.name);
38  }
39  else if (tag == "FONTBOUNDINGBOX")
40  {
41  int x, y;
42  s >> fontinfo.max_width >> fontinfo.max_height;
43  s >> x >> y;
44  fontinfo.baseline_x = - x;
45  fontinfo.baseline_y = fontinfo.max_height + y;
46  }
47  else if (tag == "STARTCHAR")
48  {
49  break;
50  }
51  }
52 }
53 
54 static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph,
55  const DataFile::fontinfo_t &fontinfo)
56 {
57  glyph.chars.clear();
58  glyph.width = 0;
59 
60  // Initialize the character contents to all 0 with proper size.
61  glyph.data.clear();
62  glyph.data.resize(fontinfo.max_width * fontinfo.max_height, 0);
63 
64  int bbx_w = fontinfo.max_width;
65  int bbx_h = fontinfo.max_height;
66  int bbx_x = - fontinfo.baseline_x;
67  int bbx_y = fontinfo.baseline_y - fontinfo.max_height;
68 
69  // Read glyph metadata
70  std::string line;
71  std::string tag;
72  while (std::getline(file, line))
73  {
74  std::istringstream s(line);
75  s >> tag;
76  tag = toupper(tag);
77 
78  if (tag == "ENCODING")
79  {
80  int c;
81  s >> c;
82  glyph.chars.push_back(c);
83  }
84  else if (tag == "DWIDTH")
85  {
86  s >> glyph.width;
87  }
88  else if (tag == "BBX")
89  {
90  s >> bbx_w >> bbx_h >> bbx_x >> bbx_y;
91  }
92  else if (tag == "BITMAP")
93  {
94  break;
95  }
96  }
97 
98  if (tag != "BITMAP")
99  return false;
100 
101  // Read glyph bits
102  int x0 = fontinfo.baseline_x + bbx_x;
103  int y = fontinfo.baseline_y - bbx_y - bbx_h;
104  for (int i = 0; i < bbx_h; i++)
105  {
106  std::getline(file, line);
107  line = toupper(line);
108 
109  for (int x = 0; x < bbx_w; x++)
110  {
111  int nibble = hextoint(line.at(x / 4));
112  uint8_t pixel = 0;
113  if (nibble & (8 >> (x % 4)))
114  pixel = 15;
115 
116  glyph.data.at(y * fontinfo.max_width + x0 + x) = pixel;
117  }
118 
119  y++;
120  }
121 
122  std::getline(file, line);
123  line = toupper(line);
124  if (line.compare(0, 7, "ENDCHAR") == 0)
125  return true;
126  else
127  return false;
128 }
129 
130 std::unique_ptr<DataFile> LoadBDF(std::istream &file)
131 {
132  DataFile::fontinfo_t fontinfo = {};
133  std::vector<DataFile::glyphentry_t> glyphtable;
134  std::vector<DataFile::dictentry_t> dictionary;
135 
136  parse_fontinfo(file, fontinfo);
137 
138  while (file)
139  {
140  DataFile::glyphentry_t glyph = {};
141  if (parse_glyph(file, glyph, fontinfo))
142  glyphtable.push_back(glyph);
143  }
144 
145  eliminate_duplicates(glyphtable);
146  crop_glyphs(glyphtable, fontinfo);
147  detect_flags(glyphtable, fontinfo);
148 
149  fontinfo.line_height = fontinfo.max_height;
150 
151  std::unique_ptr<DataFile> result(new DataFile(
152  dictionary, glyphtable, fontinfo));
153  return result;
154 }
155 
156 }