diff options
Diffstat (limited to 'tools/mcufontencoder/src/bdf_import.cc')
-rw-r--r-- | tools/mcufontencoder/src/bdf_import.cc | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/tools/mcufontencoder/src/bdf_import.cc b/tools/mcufontencoder/src/bdf_import.cc new file mode 100644 index 00000000..32deb057 --- /dev/null +++ b/tools/mcufontencoder/src/bdf_import.cc @@ -0,0 +1,156 @@ +#include "bdf_import.hh" +#include "importtools.hh" +#include <sstream> +#include <string> +#include <cctype> +#include <stdexcept> + +namespace mcufont { + +static std::string toupper(const std::string &input) +{ + std::string result; + for (char c: input) result.push_back(::toupper(c)); + return result; +} + +static int hextoint(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + throw std::domain_error("Hex digit not in range"); +} + +static void parse_fontinfo(std::istream &file, DataFile::fontinfo_t &fontinfo) +{ + std::string line; + while (std::getline(file, line)) + { + std::istringstream s(line); + std::string tag; + s >> tag; + tag = toupper(tag); + + if (tag == "FONT") + { + while (isspace(s.peek())) s.get(); + std::getline(s, fontinfo.name); + } + else if (tag == "FONTBOUNDINGBOX") + { + int x, y; + s >> fontinfo.max_width >> fontinfo.max_height; + s >> x >> y; + fontinfo.baseline_x = - x; + fontinfo.baseline_y = fontinfo.max_height + y; + } + else if (tag == "STARTCHAR") + { + break; + } + } +} + +static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph, + const DataFile::fontinfo_t &fontinfo) +{ + glyph.chars.clear(); + glyph.width = 0; + + // Initialize the character contents to all 0 with proper size. + glyph.data.clear(); + glyph.data.resize(fontinfo.max_width * fontinfo.max_height, 0); + + int bbx_w = fontinfo.max_width; + int bbx_h = fontinfo.max_height; + int bbx_x = - fontinfo.baseline_x; + int bbx_y = fontinfo.baseline_y - fontinfo.max_height; + + // Read glyph metadata + std::string line; + std::string tag; + while (std::getline(file, line)) + { + std::istringstream s(line); + s >> tag; + tag = toupper(tag); + + if (tag == "ENCODING") + { + int c; + s >> c; + glyph.chars.push_back(c); + } + else if (tag == "DWIDTH") + { + s >> glyph.width; + } + else if (tag == "BBX") + { + s >> bbx_w >> bbx_h >> bbx_x >> bbx_y; + } + else if (tag == "BITMAP") + { + break; + } + } + + if (tag != "BITMAP") + return false; + + // Read glyph bits + int x0 = fontinfo.baseline_x + bbx_x; + int y = fontinfo.baseline_y - bbx_y - bbx_h; + for (int i = 0; i < bbx_h; i++) + { + std::getline(file, line); + line = toupper(line); + + for (int x = 0; x < bbx_w; x++) + { + int nibble = hextoint(line.at(x / 4)); + uint8_t pixel = 0; + if (nibble & (8 >> (x % 4))) + pixel = 15; + + glyph.data.at(y * fontinfo.max_width + x0 + x) = pixel; + } + + y++; + } + + std::getline(file, line); + line = toupper(line); + if (line.compare(0, 7, "ENDCHAR") == 0) + return true; + else + return false; +} + +std::unique_ptr<DataFile> LoadBDF(std::istream &file) +{ + DataFile::fontinfo_t fontinfo = {}; + std::vector<DataFile::glyphentry_t> glyphtable; + std::vector<DataFile::dictentry_t> dictionary; + + parse_fontinfo(file, fontinfo); + + while (file) + { + DataFile::glyphentry_t glyph = {}; + if (parse_glyph(file, glyph, fontinfo)) + glyphtable.push_back(glyph); + } + + eliminate_duplicates(glyphtable); + crop_glyphs(glyphtable, fontinfo); + detect_flags(glyphtable, fontinfo); + + fontinfo.line_height = fontinfo.max_height; + + std::unique_ptr<DataFile> result(new DataFile( + dictionary, glyphtable, fontinfo)); + return result; +} + +} |