Added glyph loading by glyph index, passing own FT_Face handle

This commit is contained in:
Viktor Chlumský 2020-10-10 12:12:52 +02:00
parent 9d5c7c54e8
commit 38ef289f25
5 changed files with 98 additions and 27 deletions

View File

@ -34,7 +34,7 @@ static bool writeValue(FILE *file, T value) {
}
static bool writeBmpHeader(FILE *file, int width, int height, int &paddedWidth) {
paddedWidth = 3*width+3&~3;
paddedWidth = (3*width+3)&~3;
const uint32_t bitmapStart = 54;
const uint32_t bitmapSize = paddedWidth*height;
const uint32_t fileSize = bitmapStart+bitmapSize;

View File

@ -200,7 +200,7 @@ bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecifie
else {
int c = readCharS(&input);
if (c == '@') {
for (int i = 0; i < sizeof("invert-y")-1; ++i)
for (int i = 0; i < (int) sizeof("invert-y")-1; ++i)
if (input[i] != "invert-y"[i])
return false;
output.inverseYAxis = true;

View File

@ -26,14 +26,19 @@ class FreetypeHandle {
};
class FontHandle {
friend FontHandle * adoptFreetypeFont(FT_Face ftFace);
friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
friend void destroyFont(FontHandle *font);
friend bool getFontMetrics(FontMetrics &metrics, FontHandle *font);
friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font);
friend bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
friend bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance);
friend bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance);
friend bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2);
friend bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
FT_Face face;
bool ownership;
};
@ -79,6 +84,16 @@ static int ftCubicTo(const FT_Vector *control1, const FT_Vector *control2, const
return 0;
}
GlyphIndex::GlyphIndex(unsigned index) : index(index) { }
unsigned GlyphIndex::getIndex() const {
return index;
}
bool GlyphIndex::operator!() const {
return index == 0;
}
FreetypeHandle * initializeFreetype() {
FreetypeHandle *handle = new FreetypeHandle;
FT_Error error = FT_Init_FreeType(&handle->library);
@ -94,6 +109,13 @@ void deinitializeFreetype(FreetypeHandle *library) {
delete library;
}
FontHandle * adoptFreetypeFont(FT_Face ftFace) {
FontHandle *handle = new FontHandle;
handle->face = ftFace;
handle->ownership = false;
return handle;
}
FontHandle * loadFont(FreetypeHandle *library, const char *filename) {
if (!library)
return NULL;
@ -103,10 +125,12 @@ FontHandle * loadFont(FreetypeHandle *library, const char *filename) {
delete handle;
return NULL;
}
handle->ownership = true;
return handle;
}
void destroyFont(FontHandle *font) {
if (font->ownership)
FT_Done_Face(font->face);
delete font;
}
@ -133,10 +157,15 @@ bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle
return true;
}
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance) {
bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode) {
glyphIndex = GlyphIndex(FT_Get_Char_Index(font->face, unicode));
return glyphIndex.getIndex() != 0;
}
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance) {
if (!font)
return false;
FT_Error error = FT_Load_Char(font->face, unicode, FT_LOAD_NO_SCALE);
FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE);
if (error)
return false;
output.contours.clear();
@ -161,9 +190,13 @@ bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advan
return true;
}
bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2) {
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance) {
return loadGlyph(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode)), advance);
}
bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2) {
FT_Vector kerning;
if (FT_Get_Kerning(font->face, FT_Get_Char_Index(font->face, unicode1), FT_Get_Char_Index(font->face, unicode2), FT_KERNING_UNSCALED, &kerning)) {
if (FT_Get_Kerning(font->face, glyphIndex1.getIndex(), glyphIndex2.getIndex(), FT_KERNING_UNSCALED, &kerning)) {
output = 0;
return false;
}
@ -171,4 +204,8 @@ bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t
return true;
}
bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2) {
return getKerning(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode1)), GlyphIndex(FT_Get_Char_Index(font->face, unicode2)));
}
}

View File

@ -11,6 +11,18 @@ typedef unsigned unicode_t;
class FreetypeHandle;
class FontHandle;
class GlyphIndex {
public:
explicit GlyphIndex(unsigned index = 0);
unsigned getIndex() const;
bool operator!() const;
private:
unsigned index;
};
/// Global metrics of a typeface (in font units).
struct FontMetrics {
/// The size of one EM.
@ -27,6 +39,11 @@ struct FontMetrics {
FreetypeHandle * initializeFreetype();
/// Deinitializes the FreeType library.
void deinitializeFreetype(FreetypeHandle *library);
#ifdef FT_FREETYPE_H
/// Creates a FontHandle from FT_Face that was loaded by the user. destroyFont must still be called but will not affect the FT_Face.
FontHandle * adoptFreetypeFont(FT_Face ftFace);
#endif
/// Loads a font file and returns its handle.
FontHandle * loadFont(FreetypeHandle *library, const char *filename);
/// Unloads a font file.
@ -35,9 +52,13 @@ void destroyFont(FontHandle *font);
bool getFontMetrics(FontMetrics &metrics, FontHandle *font);
/// Outputs the width of the space and tab characters.
bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font);
/// Outputs the glyph index corresponding to the specified Unicode character.
bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
/// Loads the geometry of a glyph from a font file.
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *advance = NULL);
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advance = NULL);
/// Outputs the kerning distance adjustment between two specific glyphs.
bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2);
bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
}

View File

@ -45,37 +45,36 @@ static char toupper(char c) {
}
static bool parseUnsigned(unsigned &value, const char *arg) {
static char c;
char c;
return sscanf(arg, "%u%c", &value, &c) == 1;
}
static bool parseUnsignedDecOrHex(unsigned &value, const char *arg) {
if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) {
char c;
return sscanf(arg+2, "%x%c", &value, &c) == 1;
}
return parseUnsigned(value, arg);
}
static bool parseUnsignedLL(unsigned long long &value, const char *arg) {
static char c;
char c;
return sscanf(arg, "%llu%c", &value, &c) == 1;
}
static bool parseUnsignedHex(unsigned &value, const char *arg) {
static char c;
return sscanf(arg, "%x%c", &value, &c) == 1;
}
static bool parseDouble(double &value, const char *arg) {
static char c;
char c;
return sscanf(arg, "%lf%c", &value, &c) == 1;
}
static bool parseUnicode(unicode_t &unicode, const char *arg) {
unsigned uuc;
if (parseUnsigned(uuc, arg)) {
unicode = uuc;
return true;
}
if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X') && parseUnsignedHex(uuc, arg+2)) {
if (parseUnsignedDecOrHex(uuc, arg)) {
unicode = uuc;
return true;
}
if (arg[0] == '\'' && arg[1] && arg[2] == '\'' && !arg[3]) {
unicode = arg[1];
unicode = (unicode_t) (unsigned char) arg[1];
return true;
}
return false;
@ -178,7 +177,7 @@ static bool writeBinBitmapFloatBE(FILE *file, const float *values, int count)
static bool writeBinBitmapFloat(FILE *file, const float *values, int count)
#endif
{
return fwrite(values, sizeof(float), count, file) == count;
return (int) fwrite(values, sizeof(float), count, file) == count;
}
#ifdef __BIG_ENDIAN__
@ -274,7 +273,7 @@ static const char *helpText =
" -defineshape <definition>\n"
"\tDefines input shape using the ad-hoc text definition.\n"
" -font <filename.ttf> <character code>\n"
"\tLoads a single glyph from the specified font file. Format of character code is '?', 63 or 0x3F.\n"
"\tLoads a single glyph from the specified font file. Format of character code is '?', 63, 0x3F (Unicode value), or g34 (glyph index).\n"
" -shapedesc <filename.txt>\n"
"\tLoads text shape description from a file.\n"
" -stdin\n"
@ -373,6 +372,7 @@ int main(int argc, const char * const *argv) {
const char *testRender = NULL;
const char *testRenderMulti = NULL;
bool outputSpecified = false;
GlyphIndex glyphIndex;
unicode_t unicode = 0;
int svgPathIndex = 0;
@ -428,7 +428,18 @@ int main(int argc, const char * const *argv) {
ARG_CASE("-font", 2) {
inputType = FONT;
input = argv[argPos+1];
parseUnicode(unicode, argv[argPos+2]);
const char *charArg = argv[argPos+2];
unsigned gi;
switch (charArg[0]) {
case 'G': case 'g':
if (parseUnsignedDecOrHex(gi, charArg+1))
glyphIndex = GlyphIndex(gi);
break;
case 'U': case 'u':
++charArg;
default:
parseUnicode(unicode, charArg);
}
argPos += 3;
continue;
}
@ -693,8 +704,8 @@ int main(int argc, const char * const *argv) {
break;
}
case FONT: {
if (!unicode)
ABORT("No character specified! Use -font <file.ttf/otf> <character code>. Character code can be a number (65, 0x41), or a character in apostrophes ('A').");
if (!glyphIndex && !unicode)
ABORT("No character specified! Use -font <file.ttf/otf> <character code>. Character code can be a Unicode index (65, 0x41), a character in apostrophes ('A'), or a glyph index prefixed by g (g36, g0x24).");
FreetypeHandle *ft = initializeFreetype();
if (!ft) return -1;
FontHandle *font = loadFont(ft, input);
@ -702,7 +713,9 @@ int main(int argc, const char * const *argv) {
deinitializeFreetype(ft);
ABORT("Failed to load font file.");
}
if (!loadGlyph(shape, font, unicode, &glyphAdvance)) {
if (unicode)
getGlyphIndex(glyphIndex, font, unicode);
if (!loadGlyph(shape, font, glyphIndex, &glyphAdvance)) {
destroyFont(font);
deinitializeFreetype(ft);
ABORT("Failed to load glyph from font file.");