First init.
This commit is contained in:
212
libraries/mcu-renderer/tools/fontconv/import_bdf.cpp
Normal file
212
libraries/mcu-renderer/tools/fontconv/import_bdf.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* MCU renderer fontconv
|
||||
* BDF import
|
||||
*
|
||||
* (C) 2023 Gissio
|
||||
*
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
|
||||
#include "import_bdf.h"
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum BDFState
|
||||
{
|
||||
BDF_STATE_ROOT,
|
||||
BDF_STATE_PROPERTIES,
|
||||
BDF_STATE_CHAR,
|
||||
BDF_STATE_BITMAP
|
||||
};
|
||||
|
||||
static string filter(string &line)
|
||||
{
|
||||
string output;
|
||||
|
||||
for (char c : line)
|
||||
{
|
||||
if (c >= ' ')
|
||||
output += c;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static string getBDFString(string &value)
|
||||
{
|
||||
return value.substr(1, value.size() - 2);
|
||||
}
|
||||
|
||||
static bool getBDFValue(string line, string key, string &value)
|
||||
{
|
||||
if (line.size() > key.size())
|
||||
key += " ";
|
||||
|
||||
bool match = to_upper(line).starts_with(to_upper(key));
|
||||
if (match)
|
||||
value = line.substr(key.size());
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static uint8_t getHexByte(string str)
|
||||
{
|
||||
return strtoul(str.substr(0, 2).c_str(), NULL, 16);
|
||||
}
|
||||
|
||||
Font loadBDFFont(string filename,
|
||||
set<Charcode> &charcodeSet)
|
||||
{
|
||||
Font font;
|
||||
|
||||
ifstream file(filename);
|
||||
if (!file.good())
|
||||
throw runtime_error("could not open '" +
|
||||
filename +
|
||||
"'");
|
||||
|
||||
string line;
|
||||
uint32_t lineNumber = 1;
|
||||
BDFState bdfState = BDF_STATE_ROOT;
|
||||
string value;
|
||||
|
||||
Charcode charcode;
|
||||
Glyph glyph;
|
||||
uint32_t glyphY;
|
||||
|
||||
string familyName;
|
||||
string weightName;
|
||||
|
||||
while (getline(file, line))
|
||||
{
|
||||
line = filter(line);
|
||||
|
||||
switch (bdfState)
|
||||
{
|
||||
case BDF_STATE_ROOT:
|
||||
if (getBDFValue(line, "FONT", value))
|
||||
font.name = value;
|
||||
else if (getBDFValue(line, "SIZE", value))
|
||||
{
|
||||
vector<string> parameters = split(value, ' ');
|
||||
font.capHeight = stoi(parameters[0]);
|
||||
}
|
||||
else if (getBDFValue(line, "STARTPROPERTIES", value))
|
||||
bdfState = BDF_STATE_PROPERTIES;
|
||||
else if (getBDFValue(line, "STARTCHAR", value))
|
||||
bdfState = BDF_STATE_CHAR;
|
||||
|
||||
break;
|
||||
|
||||
case BDF_STATE_PROPERTIES:
|
||||
if (getBDFValue(line, "FAMILY_NAME", value))
|
||||
familyName = getBDFString(value);
|
||||
else if (getBDFValue(line, "WEIGHT_NAME", value))
|
||||
weightName = getBDFString(value);
|
||||
else if (getBDFValue(line, "COPYRIGHT", value))
|
||||
font.copyright = getBDFString(value);
|
||||
else if (getBDFValue(line, "FONT_ASCENT", value))
|
||||
font.ascent = stoi(value);
|
||||
else if (getBDFValue(line, "FONT_DESCENT", value))
|
||||
font.descent = stoi(value);
|
||||
else if (getBDFValue(line, "CAP_HEIGHT", value))
|
||||
font.capHeight = stoi(value);
|
||||
else if (getBDFValue(line, "ENDPROPERTIES", value))
|
||||
bdfState = BDF_STATE_ROOT;
|
||||
|
||||
break;
|
||||
|
||||
case BDF_STATE_CHAR:
|
||||
if (getBDFValue(line, "ENCODING", value))
|
||||
charcode = stoi(value);
|
||||
if (getBDFValue(line, "DWIDTH", value))
|
||||
{
|
||||
vector<string> parameters = split(value, ' ');
|
||||
|
||||
glyph.advance = stoi(parameters[0]);
|
||||
}
|
||||
else if (getBDFValue(line, "BBX", value))
|
||||
{
|
||||
vector<string> parameters = split(value, ' ');
|
||||
|
||||
if (parameters.size() != 4)
|
||||
throw runtime_error("bdf file invalid (line " +
|
||||
to_string(lineNumber) +
|
||||
")");
|
||||
|
||||
glyph.width = stoi(parameters[0]);
|
||||
glyph.height = stoi(parameters[1]);
|
||||
glyph.left = stoi(parameters[2]);
|
||||
glyph.bottom = stoi(parameters[3]);
|
||||
|
||||
glyph.bitmap.resize(glyph.width * glyph.height);
|
||||
}
|
||||
else if (getBDFValue(line, "BITMAP", value))
|
||||
{
|
||||
bdfState = BDF_STATE_BITMAP;
|
||||
|
||||
glyphY = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BDF_STATE_BITMAP:
|
||||
if (getBDFValue(line, "ENDCHAR", value))
|
||||
{
|
||||
bdfState = BDF_STATE_ROOT;
|
||||
|
||||
if (charcodeSet.empty() ||
|
||||
charcodeSet.contains(charcode))
|
||||
font.add(charcode, glyph);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t glyphX = 0;
|
||||
|
||||
while (line.size() >= 2)
|
||||
{
|
||||
uint8_t n = getHexByte(line);
|
||||
uint32_t pixelNum = 0;
|
||||
|
||||
while ((glyphX < glyph.width) && (pixelNum < 8))
|
||||
{
|
||||
uint8_t alpha = (n & 0x80) ? 0xff : 0;
|
||||
glyph.bitmap[glyphY * glyph.width + glyphX] = alpha;
|
||||
|
||||
n <<= 1;
|
||||
|
||||
pixelNum++;
|
||||
glyphX++;
|
||||
}
|
||||
|
||||
line = line.substr(2);
|
||||
}
|
||||
|
||||
glyphY++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lineNumber++;
|
||||
}
|
||||
|
||||
if (font.ascent == INT_MIN)
|
||||
font.ascent = font.boundingBoxBottom + font.boundingBoxHeight;
|
||||
if (font.descent == INT_MIN)
|
||||
font.descent = font.boundingBoxBottom;
|
||||
|
||||
if (familyName != "")
|
||||
font.name = familyName;
|
||||
if (weightName != "")
|
||||
{
|
||||
font.name += " ";
|
||||
font.name += weightName;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
Reference in New Issue
Block a user