Loading glyphs by glyph index

This commit is contained in:
Chlumsky 2020-10-18 14:00:24 +02:00
parent c42964a9ec
commit 60789b8cf3
15 changed files with 201 additions and 63 deletions

18
CHANGELOG.md Normal file
View File

@ -0,0 +1,18 @@
## Version 1.1 (2020-10-18)
- Updated to MSDFgen 1.8.
- Glyph geometry is now preprocessed by Skia to resolve irregularities which were previously unsupported and caused artifacts.
- The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively.
- The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA`.
- Glyphs can now also be loaded by glyph index rather than Unicode values. In the standalone version, a set of glyphs can be passed by `-glyphset` in place of `-charset`.
- Glyphs not present in the font should now be correctly skipped instead of producing a placeholder symbol.
- Added `-threads` argument to set the number of concurrent threads used during distance field generation.
### Version 1.0.1 (2020-03-09)
- Updated to MSDFgen 1.7.1.
## Version 1.0 (2020-03-08)
- Initial release.

View File

@ -3,19 +3,17 @@
This is a utility for generating compact font atlases using [MSDFgen](https://github.com/Chlumsky/msdfgen).
It can read TTF and OTF font files, select a subset of characters, generate distance fields or bitmaps for each, and tightly pack them into an atlas bitmap, which can be e.g. used as a texture in video games. The atlas can be exported as an image file or an [Artery Font](https://github.com/Chlumsky/artery-font-format) file, and its layout written into a CSV or structured JSON file.
The atlas generator loads a subset of glyphs from a TTF or OTF font file, generates a distance field for each of them, and tightly packs them into an atlas bitmap (example below). The finished atlas and/or its layout metadata can be exported as an [Artery Font](https://github.com/Chlumsky/artery-font-format) file, a plain image file, a CSV sheet or a structured JSON file.
![Atlas example](https://user-images.githubusercontent.com/18639794/76163889-811f2e80-614a-11ea-9b28-1eed54dbb899.png)
## Getting started
A font atlas is typically stored in texture memory and used to draw text in real-time rendering contexts such as video games.
This project can be used either as a library or as a console program.
To start using the program immediately, there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdf-atlas-gen/releases).
To build the project, you may use the included [Visual Studio solution](msdf-atlas-gen.sln) or the [Unix Makefile](Makefile).
- See what's new in the [changelog](CHANGELOG.md).
## Atlas types
The utility can generate the atlas bitmap in the following six ways:
The atlas generator can generate the following six types of atlases.
| |Hard mask|Soft mask|SDF|PSDF|MSDF|MTSDF|
|-|-|-|-|-|-|-|
@ -32,12 +30,21 @@ Notes:
- *Soft effects* refers to the support of effects that use true distance, such as glows, rounded borders, or simplified shadows.
- *Hard effects* refers to the support of effects that use pseudo-distance, such as mitered borders or thickness adjustment.
## Getting started
This project can be used either as a library or as a standalone console program.
To start using the program immediately, there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdf-atlas-gen/releases).
To build the project, you may use the included [Visual Studio solution](msdf-atlas-gen.sln) or the [Unix Makefile](Makefile).
## Command line arguments
Use the following command line arguments for the standalone version of the atlas generator.
### Input
- `-font <fontfile.ttf/otf>` &ndash; sets the input font file.
- `-charset <charset.txt>` &ndash; sets the character set. The ASCII charset will be used if not specified. See [the syntax specification](#character-set-specification-syntax) of `charset.txt`.
- `-glyphset <glyphset.txt>` &ndash; sets the set of input glyphs using their indices within the font file. See [the syntax specification](#glyph-set-specification).
### Bitmap atlas type
@ -123,3 +130,7 @@ Additionally, the include directive can be used to include other charset files a
It must be written on a separate line:
`@include "base-charset.txt"`
### Glyph set specification
The syntax of the glyph set specification is mostly the same as that of a character set, but only numeric values (decimal and hexadecimal) are allowed.

View File

@ -25,7 +25,7 @@ public:
std::set<unicode_t>::const_iterator end() const;
/// Load character set from a text file with the correct syntax
bool load(const char *filename);
bool load(const char *filename, bool disableCharLiterals = false);
private:
std::set<unicode_t> codepoints;

View File

@ -1,13 +1,11 @@
#pragma once
#include "types.h"
namespace msdf_atlas {
/// The glyph box - its bounds in plane and atlas
struct GlyphBox {
unicode_t codepoint;
int index;
double advance;
struct {
double l, b, r, t;

View File

@ -6,11 +6,12 @@
namespace msdf_atlas {
GlyphGeometry::GlyphGeometry() : codepoint(), bounds(), advance(), box() { }
GlyphGeometry::GlyphGeometry() : index(), codepoint(), bounds(), advance(), box() { }
bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry) {
if (font && msdfgen::loadGlyph(shape, font, codepoint, &advance) && shape.validate()) {
this->codepoint = codepoint;
bool GlyphGeometry::load(msdfgen::FontHandle *font, msdfgen::GlyphIndex index, bool preprocessGeometry) {
if (font && msdfgen::loadGlyph(shape, font, index, &advance) && shape.validate()) {
this->index = index.getIndex();
codepoint = 0;
#ifdef MSDFGEN_USE_SKIA
if (preprocessGeometry)
msdfgen::resolveShapeGeometry(shape);
@ -33,6 +34,17 @@ bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool pr
return false;
}
bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry) {
msdfgen::GlyphIndex index;
if (msdfgen::getGlyphIndex(index, font, codepoint)) {
if (load(font, index, preprocessGeometry)) {
this->codepoint = codepoint;
return true;
}
}
return false;
}
void GlyphGeometry::edgeColoring(double angleThreshold, unsigned long long seed) {
msdfgen::edgeColoringInkTrap(shape, angleThreshold, seed);
}
@ -62,10 +74,28 @@ void GlyphGeometry::placeBox(int x, int y) {
box.rect.x = x, box.rect.y = y;
}
int GlyphGeometry::getIndex() const {
return index;
}
msdfgen::GlyphIndex GlyphGeometry::getGlyphIndex() const {
return msdfgen::GlyphIndex(index);
}
unicode_t GlyphGeometry::getCodepoint() const {
return codepoint;
}
int GlyphGeometry::getIdentifier(GlyphIdentifierType type) const {
switch (type) {
case GlyphIdentifierType::GLYPH_INDEX:
return index;
case GlyphIdentifierType::UNICODE_CODEPOINT:
return (int) codepoint;
}
return 0;
}
const msdfgen::Shape & GlyphGeometry::getShape() const {
return shape;
}
@ -121,7 +151,7 @@ bool GlyphGeometry::isWhitespace() const {
GlyphGeometry::operator GlyphBox() const {
GlyphBox box;
box.codepoint = codepoint;
box.index = index;
box.advance = advance;
getQuadPlaneBounds(box.bounds.l, box.bounds.b, box.bounds.r, box.bounds.t);
box.rect.x = this->box.rect.x, box.rect.y = this->box.rect.y, box.rect.w = this->box.rect.w, box.rect.h = this->box.rect.h;

View File

@ -14,6 +14,7 @@ class GlyphGeometry {
public:
GlyphGeometry();
/// Loads glyph geometry from font
bool load(msdfgen::FontHandle *font, msdfgen::GlyphIndex index, bool preprocessGeometry = true);
bool load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry = true);
/// Applies edge coloring to glyph shape
void edgeColoring(double angleThreshold, unsigned long long seed);
@ -21,8 +22,14 @@ public:
void wrapBox(double scale, double range, double miterLimit);
/// Sets the glyph's box's position in the atlas
void placeBox(int x, int y);
/// Returns the glyph's Unicode index
/// Returns the glyph's index within the font
int getIndex() const;
/// Returns the glyph's index as a msdfgen::GlyphIndex
msdfgen::GlyphIndex getGlyphIndex() const;
/// Returns the Unicode codepoint represented by the glyph or 0 if unknown
unicode_t getCodepoint() const;
/// Returns the glyph's identifier specified by the supplied identifier type
int getIdentifier(GlyphIdentifierType type) const;
/// Returns the glyph's shape
const msdfgen::Shape & getShape() const;
/// Returns the glyph's advance
@ -47,6 +54,7 @@ public:
operator GlyphBox() const;
private:
int index;
unicode_t codepoint;
msdfgen::Shape shape;
msdfgen::Shape::Bounds bounds;

View File

@ -24,6 +24,16 @@ static artery_font::ImageType convertImageType(ImageType imageType) {
return artery_font::IMAGE_NONE;
}
static artery_font::CodepointType convertCodepointType(GlyphIdentifierType glyphIdentifierType) {
switch (glyphIdentifierType) {
case GlyphIdentifierType::GLYPH_INDEX:
return artery_font::CP_INDEXED;
case GlyphIdentifierType::UNICODE_CODEPOINT:
return artery_font::CP_UNICODE;
}
return artery_font::CP_UNSPECIFIED;
}
template <typename T, int N>
static bool encodeTiff(std::vector<byte> &output, const msdfgen::BitmapConstRef<T, N> &atlas) {
// TODO
@ -43,7 +53,7 @@ artery_font::PixelFormat getPixelFormat<float>() {
}
template <typename REAL, typename T, int N>
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<T, N> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename) {
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties) {
artery_font::StdArteryFont<REAL> arfont = { };
arfont.metadataFormat = artery_font::METADATA_NONE;
@ -53,11 +63,11 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
return false;
double fsScale = 1/fontMetrics.emSize;
artery_font::StdFontVariant<REAL> fontVariant = { };
fontVariant.codepointType = artery_font::CP_UNICODE;
fontVariant.imageType = convertImageType(imageType);
fontVariant.metrics.fontSize = REAL(fontSize);
if (imageType != ImageType::HARD_MASK)
fontVariant.metrics.distanceRange = REAL(pxRange);
fontVariant.codepointType = convertCodepointType(properties.glyphIdentifierType);
fontVariant.imageType = convertImageType(properties.imageType);
fontVariant.metrics.fontSize = REAL(properties.fontSize);
if (properties.imageType != ImageType::HARD_MASK)
fontVariant.metrics.distanceRange = REAL(properties.pxRange);
fontVariant.metrics.emSize = REAL(fsScale*fontMetrics.emSize);
fontVariant.metrics.ascender = REAL(fsScale*fontMetrics.ascenderY);
fontVariant.metrics.descender = REAL(fsScale*fontMetrics.descenderY);
@ -67,7 +77,7 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
fontVariant.glyphs = artery_font::StdList<artery_font::Glyph<REAL> >(glyphCount);
for (int i = 0; i < glyphCount; ++i) {
artery_font::Glyph<REAL> &glyph = fontVariant.glyphs[i];
glyph.codepoint = glyphs[i].getCodepoint();
glyph.codepoint = glyphs[i].getIdentifier(properties.glyphIdentifierType);
glyph.image = 0;
double l, b, r, t;
glyphs[i].getQuadPlaneBounds(l, b, r, t);
@ -84,10 +94,10 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
glyph.advance.v = REAL(0);
for (int j = 0; j < glyphCount; ++j) {
double kerning;
if (msdfgen::getKerning(kerning, font, glyphs[i].getCodepoint(), glyphs[j].getCodepoint()) && kerning) {
if (msdfgen::getKerning(kerning, font, glyphs[i].getGlyphIndex(), glyphs[j].getGlyphIndex()) && kerning) {
artery_font::KernPair<REAL> kernPair = { };
kernPair.codepoint1 = glyphs[i].getCodepoint();
kernPair.codepoint2 = glyphs[j].getCodepoint();
kernPair.codepoint1 = glyphs[i].getIdentifier(properties.glyphIdentifierType);
kernPair.codepoint2 = glyphs[j].getIdentifier(properties.glyphIdentifierType);
kernPair.advance.h = REAL(fsScale*kerning);
fontVariant.kernPairs.vector.push_back((artery_font::KernPair<REAL> &&) kernPair);
}
@ -101,8 +111,8 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
image.width = atlas.width;
image.height = atlas.height;
image.channels = N;
image.imageType = convertImageType(imageType);
switch (imageFormat) {
image.imageType = convertImageType(properties.imageType);
switch (properties.imageFormat) {
case ImageFormat::PNG:
image.encoding = artery_font::IMAGE_PNG;
image.pixelFormat = artery_font::PIXEL_UNSIGNED8;
@ -139,11 +149,11 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
return artery_font::writeFile(arfont, filename);
}
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<byte, 1> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<byte, 3> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<byte, 4> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<float, 1> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<float, 3> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<float, 4> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<byte, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<byte, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<byte, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<float, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<float, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<float, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
}

View File

@ -8,8 +8,16 @@
namespace msdf_atlas {
struct ArteryFontExportProperties {
GlyphIdentifierType glyphIdentifierType;
double fontSize;
double pxRange;
ImageType imageType;
ImageFormat imageFormat;
};
/// Encodes the atlas bitmap and its layout into an Artery Atlas Font file
template <typename REAL, typename T, int N>
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<T, N> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties);
}

View File

@ -96,7 +96,7 @@ static std::string combinePath(const char *basePath, const char *relPath) {
return std::string(basePath, lastSlash+1)+relPath;
}
bool Charset::load(const char *filename) {
bool Charset::load(const char *filename, bool disableCharLiterals) {
if (FILE *f = fopen(filename, "rb")) {
@ -125,7 +125,7 @@ bool Charset::load(const char *filename) {
goto FAIL;
switch (state) {
case CLEAR:
if (cp > 0)
if (cp >= 0)
add((unicode_t) cp);
state = TIGHT;
break;
@ -144,7 +144,7 @@ bool Charset::load(const char *filename) {
buffer.clear();
continue; // next character already read
case '\'': // single UTF-8 character
if (!(state == CLEAR || state == RANGE_BRACKET || state == RANGE_SEPARATOR))
if (!(state == CLEAR || state == RANGE_BRACKET || state == RANGE_SEPARATOR) || disableCharLiterals)
goto FAIL;
if (!readString(buffer, f, '\''))
goto FAIL;
@ -173,7 +173,7 @@ bool Charset::load(const char *filename) {
buffer.clear();
break;
case '"': // string of UTF-8 characters
if (state != CLEAR)
if (state != CLEAR || disableCharLiterals)
goto FAIL;
if (!readString(buffer, f, '"'))
goto FAIL;

View File

@ -5,7 +5,7 @@
namespace msdf_atlas {
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, double emSize, const char *filename) {
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double emSize, const char *filename) {
FILE *f = fopen(filename, "w");
if (!f)
return false;
@ -13,7 +13,7 @@ bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, double emSize, const
double fsScale = 1/emSize;
for (int i = 0; i < glyphCount; ++i) {
double l, b, r, t;
fprintf(f, "%u,%.17g,", glyphs[i].getCodepoint(), fsScale*glyphs[i].getAdvance());
fprintf(f, "%d,%.17g,", glyphs[i].getIdentifier(glyphIdentifierType), fsScale*glyphs[i].getAdvance());
glyphs[i].getQuadPlaneBounds(l, b, r, t);
fprintf(f, "%.17g,%.17g,%.17g,%.17g,", fsScale*l, fsScale*b, fsScale*r, fsScale*t);
glyphs[i].getQuadAtlasBounds(l, b, r, t);

View File

@ -1,14 +1,15 @@
#pragma once
#include "types.h"
#include "GlyphGeometry.h"
namespace msdf_atlas {
/**
* Writes the positioning data and atlas layout of the glyphs into a CSV file
* The columns are: Unicode index, horizontal advance, plane bounds (l, b, r, t), atlas bounds (l, b, r, t)
* The columns are: glyph identifier (index or Unicode), horizontal advance, plane bounds (l, b, r, t), atlas bounds (l, b, r, t)
*/
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, double emSize, const char *filename);
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double emSize, const char *filename);
}

View File

@ -21,7 +21,7 @@ static const char * imageTypeString(ImageType type) {
return nullptr;
}
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename) {
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename) {
msdfgen::FontMetrics fontMetrics;
if (!msdfgen::getFontMetrics(fontMetrics, font))
return false;
@ -56,7 +56,14 @@ bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyp
fputs("\"glyphs\":[", f);
for (int i = 0; i < glyphCount; ++i) {
fputs(i == 0 ? "{" : ",{", f);
switch (glyphIdentifierType) {
case GlyphIdentifierType::GLYPH_INDEX:
fprintf(f, "\"index\":%d,", glyphs[i].getIndex());
break;
case GlyphIdentifierType::UNICODE_CODEPOINT:
fprintf(f, "\"unicode\":%u,", glyphs[i].getCodepoint());
break;
}
fprintf(f, "\"advance\":%.17g", fsScale*glyphs[i].getAdvance());
double l, b, r, t;
glyphs[i].getQuadPlaneBounds(l, b, r, t);

View File

@ -9,6 +9,6 @@
namespace msdf_atlas {
/// Writes the font and glyph metrics and atlas layout data into a comprehensive JSON file
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename);
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename);
}

View File

@ -44,6 +44,8 @@ INPUT SPECIFICATION
Specifies the input TrueType / OpenType font file. This is required.
-charset <filename>
Specifies the input character set. Refer to the documentation for format of charset specification. Defaults to ASCII.
-glyphset <filename>
Specifies the set of input glyphs as glyph indices within the font file.
ATLAS CONFIGURATION
-type <hardmask / softmask / sdf / psdf / msdf / mtsdf>
@ -145,7 +147,19 @@ static bool cmpExtension(const char *path, const char *ext) {
return true;
}
static void loadGlyphs(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Charset &charset, bool preprocessGeometry) {
static void loadGlyphsByIndex(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Charset &charset, bool preprocessGeometry) {
glyphs.clear();
glyphs.reserve(charset.size());
for (unicode_t cp : charset) {
GlyphGeometry glyph;
if (glyph.load(font, msdfgen::GlyphIndex(cp), preprocessGeometry))
glyphs.push_back((GlyphGeometry &&) glyph);
else
printf("Glyph # 0x%X missing\n", cp);
}
}
static void loadGlyphsByUnicode(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Charset &charset, bool preprocessGeometry) {
glyphs.clear();
glyphs.reserve(charset.size());
for (unicode_t cp : charset) {
@ -158,6 +172,7 @@ static void loadGlyphs(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *
}
struct Configuration {
GlyphIdentifierType glyphIdentifierType;
ImageType imageType;
ImageFormat imageFormat;
int width, height;
@ -197,7 +212,13 @@ static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, msdfgen::FontHan
}
if (config.arteryFontFilename) {
if (exportArteryFont<float>(font, glyphs.data(), glyphs.size(), config.emSize, config.pxRange, bitmap, config.imageType, config.imageFormat, config.arteryFontFilename))
ArteryFontExportProperties arfontProps;
arfontProps.glyphIdentifierType = config.glyphIdentifierType;
arfontProps.fontSize = config.emSize;
arfontProps.pxRange = config.pxRange;
arfontProps.imageType = config.imageType;
arfontProps.imageFormat = config.imageFormat;
if (exportArteryFont<float>(font, glyphs.data(), glyphs.size(), bitmap, config.arteryFontFilename, arfontProps))
puts("Artery Font file generated.");
else {
success = false;
@ -215,6 +236,7 @@ int main(int argc, const char * const *argv) {
Configuration config = { };
const char *fontFilename = nullptr;
const char *charsetFilename = nullptr;
config.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
config.imageType = ImageType::MSDF;
config.imageFormat = ImageFormat::UNSPECIFIED;
const char *imageFormatName = nullptr;
@ -299,6 +321,13 @@ int main(int argc, const char * const *argv) {
}
ARG_CASE("-charset", 1) {
charsetFilename = argv[++argPos];
config.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
++argPos;
continue;
}
ARG_CASE("-glyphset", 1) {
charsetFilename = argv[++argPos];
config.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
++argPos;
continue;
}
@ -593,17 +622,24 @@ int main(int argc, const char * const *argv) {
// Load character set
Charset charset;
if (charsetFilename) {
if (!charset.load(charsetFilename))
ABORT("Failed to load character set specification.");
if (!charset.load(charsetFilename, config.glyphIdentifierType != GlyphIdentifierType::UNICODE_CODEPOINT))
ABORT(config.glyphIdentifierType == GlyphIdentifierType::GLYPH_INDEX ? "Failed to load glyph set specification." : "Failed to load character set specification.");
} else
charset = Charset::ASCII;
if (charset.empty())
ABORT("No character set loaded.");
// Load glyphs
std::vector<GlyphGeometry> glyphs;
loadGlyphs(glyphs, font, charset, config.preprocessGeometry);
printf("Loaded geometry of %d out of %d characters.\n", (int) glyphs.size(), (int) charset.size());
switch (config.glyphIdentifierType) {
case GlyphIdentifierType::GLYPH_INDEX:
loadGlyphsByIndex(glyphs, font, charset, config.preprocessGeometry);
break;
case GlyphIdentifierType::UNICODE_CODEPOINT:
loadGlyphsByUnicode(glyphs, font, charset, config.preprocessGeometry);
break;
}
if (glyphs.empty())
ABORT("No glyphs loaded.");
printf("Loaded geometry of %d out of %d %s.\n", (int) glyphs.size(), (int) charset.size(), config.glyphIdentifierType == GlyphIdentifierType::GLYPH_INDEX ? "glyphs" : "characters");
// Determine final atlas dimensions, scale and range, pack glyphs
{
@ -709,7 +745,7 @@ int main(int argc, const char * const *argv) {
}
if (config.csvFilename) {
if (exportCSV(glyphs.data(), glyphs.size(), fontMetrics.emSize, config.csvFilename))
if (exportCSV(glyphs.data(), glyphs.size(), config.glyphIdentifierType, fontMetrics.emSize, config.csvFilename))
puts("Glyph layout written into CSV file.");
else {
result = 1;
@ -717,7 +753,7 @@ int main(int argc, const char * const *argv) {
}
}
if (config.jsonFilename) {
if (exportJSON(font, glyphs.data(), glyphs.size(), config.emSize, config.pxRange, config.width, config.height, config.imageType, config.jsonFilename))
if (exportJSON(font, glyphs.data(), glyphs.size(), config.glyphIdentifierType, config.emSize, config.pxRange, config.width, config.height, config.imageType, config.jsonFilename))
puts("Glyph layout and metadata written into JSON file.");
else {
result = 1;
@ -726,6 +762,7 @@ int main(int argc, const char * const *argv) {
}
if (config.shadronPreviewFilename && config.shadronPreviewText) {
if (config.glyphIdentifierType == GlyphIdentifierType::UNICODE_CODEPOINT) {
std::vector<unicode_t> previewText;
utf8Decode(previewText, config.shadronPreviewText);
previewText.push_back(0);
@ -735,6 +772,10 @@ int main(int argc, const char * const *argv) {
result = 1;
puts("Failed to generate Shadron preview file.");
}
} else {
result = 1;
puts("Shadron preview not supported in -glyphset mode.");
}
}
return result;

View File

@ -37,4 +37,10 @@ enum class ImageFormat {
BINARY_FLOAT_BE
};
/// Glyph identification
enum class GlyphIdentifierType {
GLYPH_INDEX,
UNICODE_CODEPOINT
};
}