mirror of https://github.com/Chlumsky/msdfgen.git
Variable fonts (#164)
Co-authored-by: themancalledjakob <github@jrkb.land>
This commit is contained in:
parent
3300ab6869
commit
99559ac1db
|
|
@ -1,22 +1,26 @@
|
||||||
|
|
||||||
#include "import-font.h"
|
#include "import-font.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstring>
|
||||||
#include <queue>
|
#include <vector>
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
#include FT_OUTLINE_H
|
#include FT_OUTLINE_H
|
||||||
|
#include FT_MULTIPLE_MASTERS_H
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
#define REQUIRE(cond) { if (!(cond)) return false; }
|
|
||||||
#define F26DOT6_TO_DOUBLE(x) (1/64.*double(x))
|
#define F26DOT6_TO_DOUBLE(x) (1/64.*double(x))
|
||||||
|
#define F16DOT16_TO_DOUBLE(x) (1/65536.*double(x))
|
||||||
|
#define DOUBLE_TO_F16DOT16(x) FT_Fixed(65536.*x)
|
||||||
|
|
||||||
class FreetypeHandle {
|
class FreetypeHandle {
|
||||||
friend FreetypeHandle * initializeFreetype();
|
friend FreetypeHandle * initializeFreetype();
|
||||||
friend void deinitializeFreetype(FreetypeHandle *library);
|
friend void deinitializeFreetype(FreetypeHandle *library);
|
||||||
friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
|
friend FontHandle * loadFont(FreetypeHandle *library, const char *filename);
|
||||||
friend FontHandle * loadFontData(FreetypeHandle *library, const byte *data, int length);
|
friend FontHandle * loadFontData(FreetypeHandle *library, const byte *data, int length);
|
||||||
|
friend bool setFontVariationAxis(FreetypeHandle *library, FontHandle *font, const char *name, double coordinate);
|
||||||
|
friend bool listFontVariationAxes(std::vector<FontVariationAxis> &axes, FreetypeHandle *library, FontHandle *font);
|
||||||
|
|
||||||
FT_Library library;
|
FT_Library library;
|
||||||
|
|
||||||
|
|
@ -34,6 +38,8 @@ class FontHandle {
|
||||||
friend bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, 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, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2);
|
||||||
friend bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
|
friend bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
|
||||||
|
friend bool setFontVariationAxis(FreetypeHandle *library, FontHandle *font, const char *name, double coordinate);
|
||||||
|
friend bool listFontVariationAxes(std::vector<FontVariationAxis> &axes, FreetypeHandle *library, FontHandle *font);
|
||||||
|
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
bool ownership;
|
bool ownership;
|
||||||
|
|
@ -215,4 +221,48 @@ bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t
|
||||||
return getKerning(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode1)), GlyphIndex(FT_Get_Char_Index(font->face, unicode2)));
|
return getKerning(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode1)), GlyphIndex(FT_Get_Char_Index(font->face, unicode2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setFontVariationAxis(FreetypeHandle *library, FontHandle *font, const char *name, double coordinate) {
|
||||||
|
bool success = false;
|
||||||
|
if (font->face->face_flags&FT_FACE_FLAG_MULTIPLE_MASTERS) {
|
||||||
|
FT_MM_Var *master = NULL;
|
||||||
|
if (FT_Get_MM_Var(font->face, &master))
|
||||||
|
return false;
|
||||||
|
if (master && master->num_axis) {
|
||||||
|
std::vector<FT_Fixed> coords(master->num_axis);
|
||||||
|
if (!FT_Get_Var_Design_Coordinates(font->face, FT_UInt(coords.size()), &coords[0])) {
|
||||||
|
for (FT_UInt i = 0; i < master->num_axis; ++i) {
|
||||||
|
if (!strcmp(name, master->axis[i].name)) {
|
||||||
|
coords[i] = DOUBLE_TO_F16DOT16(coordinate);
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FT_Set_Var_Design_Coordinates(font->face, FT_UInt(coords.size()), &coords[0]))
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
FT_Done_MM_Var(library->library, master);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool listFontVariationAxes(std::vector<FontVariationAxis> &axes, FreetypeHandle *library, FontHandle *font) {
|
||||||
|
if (font->face->face_flags&FT_FACE_FLAG_MULTIPLE_MASTERS) {
|
||||||
|
FT_MM_Var *master = NULL;
|
||||||
|
if (FT_Get_MM_Var(font->face, &master))
|
||||||
|
return false;
|
||||||
|
axes.resize(master->num_axis);
|
||||||
|
for (FT_UInt i = 0; i < master->num_axis; i++) {
|
||||||
|
FontVariationAxis &axis = axes[i];
|
||||||
|
axis.name = master->axis[i].name;
|
||||||
|
axis.minValue = master->axis[i].minimum;
|
||||||
|
axis.maxValue = master->axis[i].maximum;
|
||||||
|
axis.defaultValue = master->axis[i].def;
|
||||||
|
}
|
||||||
|
FT_Done_MM_Var(library->library, master);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,18 @@ struct FontMetrics {
|
||||||
double underlineY, underlineThickness;
|
double underlineY, underlineThickness;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A structure to model a given axis of a variable font.
|
||||||
|
struct FontVariationAxis {
|
||||||
|
/// The name of the variation axis.
|
||||||
|
const char *name;
|
||||||
|
/// The axis's minimum coordinate value.
|
||||||
|
double minValue;
|
||||||
|
/// The axis's maximum coordinate value.
|
||||||
|
double maxValue;
|
||||||
|
/// The axis's default coordinate value. FreeType computes meaningful default values for Adobe MM fonts.
|
||||||
|
double defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
/// Initializes the FreeType library.
|
/// Initializes the FreeType library.
|
||||||
FreetypeHandle * initializeFreetype();
|
FreetypeHandle * initializeFreetype();
|
||||||
/// Deinitializes the FreeType library.
|
/// Deinitializes the FreeType library.
|
||||||
|
|
@ -62,5 +74,9 @@ bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *advan
|
||||||
/// Outputs the kerning distance adjustment between two specific glyphs.
|
/// 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, GlyphIndex glyphIndex1, GlyphIndex glyphIndex2);
|
||||||
bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
|
bool getKerning(double &output, FontHandle *font, unicode_t unicode1, unicode_t unicode2);
|
||||||
|
/// Sets a single variation axis of a variable font.
|
||||||
|
bool setFontVariationAxis(FreetypeHandle *library, FontHandle *font, const char *name, double coordinate);
|
||||||
|
/// Lists names and ranges of variation axes of a variable font.
|
||||||
|
bool listFontVariationAxes(std::vector<FontVariationAxis> &axes, FreetypeHandle *library, FontHandle *font);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
main.cpp
38
main.cpp
|
|
@ -13,6 +13,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "msdfgen.h"
|
#include "msdfgen.h"
|
||||||
#include "msdfgen-ext.h"
|
#include "msdfgen-ext.h"
|
||||||
|
|
@ -135,6 +136,29 @@ static void parseColoring(Shape &shape, const char *edgeAssignment) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FontHandle * loadVarFont(FreetypeHandle *library, const char *filename) {
|
||||||
|
std::string buffer;
|
||||||
|
while (*filename && *filename != '?')
|
||||||
|
buffer.push_back(*filename++);
|
||||||
|
FontHandle *font = loadFont(library, buffer.c_str());
|
||||||
|
if (*filename++ == '?') {
|
||||||
|
do {
|
||||||
|
buffer.clear();
|
||||||
|
while (*filename && *filename != '=')
|
||||||
|
buffer.push_back(*filename++);
|
||||||
|
if (*filename == '=') {
|
||||||
|
double value = 0;
|
||||||
|
int skip = 0;
|
||||||
|
if (sscanf(++filename, "%lf%n", &value, &skip) == 1) {
|
||||||
|
setFontVariationAxis(library, font, buffer.c_str(), value);
|
||||||
|
filename += skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (*filename++ == '&');
|
||||||
|
}
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
static void invertColor(const BitmapRef<float, N> &bitmap) {
|
static void invertColor(const BitmapRef<float, N> &bitmap) {
|
||||||
const float *end = bitmap.pixels+N*bitmap.width*bitmap.height;
|
const float *end = bitmap.pixels+N*bitmap.width*bitmap.height;
|
||||||
|
|
@ -295,6 +319,8 @@ static const char *helpText =
|
||||||
"\tReads text shape description from the standard input.\n"
|
"\tReads text shape description from the standard input.\n"
|
||||||
" -svg <filename.svg>\n"
|
" -svg <filename.svg>\n"
|
||||||
"\tLoads the last vector path found in the specified SVG file.\n"
|
"\tLoads the last vector path found in the specified SVG file.\n"
|
||||||
|
" -varfont <filename and variables> <character code>\n"
|
||||||
|
"\tLoads a single glyph from a variable font. Specify variable values as x.ttf?var1=0.5&var2=1\n"
|
||||||
"\n"
|
"\n"
|
||||||
// Keep alphabetical order!
|
// Keep alphabetical order!
|
||||||
"OPTIONS\n"
|
"OPTIONS\n"
|
||||||
|
|
@ -408,6 +434,7 @@ int main(int argc, const char * const *argv) {
|
||||||
NONE,
|
NONE,
|
||||||
SVG,
|
SVG,
|
||||||
FONT,
|
FONT,
|
||||||
|
VAR_FONT,
|
||||||
DESCRIPTION_ARG,
|
DESCRIPTION_ARG,
|
||||||
DESCRIPTION_STDIN,
|
DESCRIPTION_STDIN,
|
||||||
DESCRIPTION_FILE
|
DESCRIPTION_FILE
|
||||||
|
|
@ -496,8 +523,8 @@ int main(int argc, const char * const *argv) {
|
||||||
argPos += 2;
|
argPos += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ARG_CASE("-font", 2) {
|
//ARG_CASE -font, -varfont
|
||||||
inputType = FONT;
|
if (argPos+2 < argc && ((!strcmp(arg, "-font") && (inputType = FONT)) || (!strcmp(arg, "-varfont") && (inputType = VAR_FONT)))) {
|
||||||
input = argv[argPos+1];
|
input = argv[argPos+1];
|
||||||
const char *charArg = argv[argPos+2];
|
const char *charArg = argv[argPos+2];
|
||||||
unsigned gi;
|
unsigned gi;
|
||||||
|
|
@ -840,12 +867,13 @@ int main(int argc, const char * const *argv) {
|
||||||
ABORT("Failed to load shape from SVG file.");
|
ABORT("Failed to load shape from SVG file.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FONT: {
|
case FONT: case VAR_FONT: {
|
||||||
if (!glyphIndexSpecified && !unicode)
|
if (!glyphIndexSpecified && !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).");
|
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();
|
FreetypeHandle *ft = initializeFreetype();
|
||||||
if (!ft) return -1;
|
if (!ft)
|
||||||
FontHandle *font = loadFont(ft, input);
|
return -1;
|
||||||
|
FontHandle *font = inputType == VAR_FONT ? loadVarFont(ft, input) : loadFont(ft, input);
|
||||||
if (!font) {
|
if (!font) {
|
||||||
deinitializeFreetype(ft);
|
deinitializeFreetype(ft);
|
||||||
ABORT("Failed to load font file.");
|
ABORT("Failed to load font file.");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue