这是一个使用 MSDFgen 生成紧凑字体图集的实用工具。
该图集生成器从 TTF 或 OTF 字体文件中加载字形的子集,为每个字形生成距离场,并将它们紧密地打包到图集位图中(如下例所示)。完成的图集和/或其布局元数据可以导出为 Artery Font 文件、纯图像文件、CSV 表格或结构化的 JSON 文件。
字体图集通常存储在纹理内存中,用于在实时渲染环境(如视频游戏)中绘制文本。
该图集生成器可以生成以下六种类型的图集。
硬掩码 | 软掩码 | SDF | PSDF | MSDF | MTSDF | |
---|---|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
通道 | 1 (1 位) | 1 | 1 | 1 | 3 | 4 |
抗锯齿 | - | 是 | 是 | 是 | 是 | 是 |
可伸缩性 | - | - | 是 | 是 | 是 | 是 |
锐角 | - | - | - | - | 是 | 是 |
柔和效果 | - | - | 是 | - | - | 是 |
硬朗效果 | - | - | - | 是 | 是 | 是 |
注释
此项目既可以用作库,也可以用作独立的控制台程序。有关如何将其用作库的示例,请参见页面底部。要立即开始使用该程序,可以在 “发布”部分 中下载 Windows 二进制文件。要从源代码构建项目,可以使用包含的 CMake 脚本。在其默认配置中,它需要 vcpkg 作为第三方库依赖项的提供者。如果将环境变量 VCPKG_ROOT
设置为 vcpkg 目录,CMake 配置将负责从 vcpkg 获取所有必需的软件包。
对于独立版本的图集生成器,请使用以下命令行参数。
-font <fontfile.ttf/otf>
(必需)– 设置输入字体文件。-varfont <fontfile.ttf/otf?var0=value0&var1=value1>
来配置可变字体。-charset <charset.txt>
– 设置字符集。如果未指定,将使用 ASCII 字符集。请参阅 charset.txt
的 语法规范。-glyphset <glyphset.txt>
– 使用字体文件中的索引设置输入字形集。请参阅 语法规范。-fontscale <scale>
– 将缩放变换应用于字体的字形。主要用于在单个图集中生成多个大小,否则请使用 -size
。-fontname <name>
– 为字体设置一个名称,该名称将作为元数据存储在某些输出文件中。-and
– 分隔要合并到单个图集中的多个输入。-type <type>
– 参见 图集类型
<type>
可以是以下之一
hardmask
– 非抗锯齿二值图像softmask
– 抗锯齿图像sdf
– 真正的有向距离场 (SDF)psdf
– 伪距离场msdf
(默认)– 多通道有向距离场 (MSDF)mtsdf
– MSDF 和 alpha 通道中真正的 SDF 的组合-format <format>
<format>
可以是以下之一
png
– 压缩的 PNG 图像bmp
– 未压缩的 BMP 图像tiff
– 未压缩的浮点 TIFF 图像text
– 纯文本中的像素值序列textfloat
– 纯文本中的浮点像素值序列bin
– 编码为原始字节数据的像素值序列binfloat
– 编码为原始 32 位浮点值的像素值序列-dimensions <width> <height>
– 设置固定的图集尺寸
或者,如果设置了尺寸约束,则可以自动选择最小可能的尺寸
-pots
– 2 的幂的正方形-potr
– 2 的幂的正方形或矩形 (2:1)-square
– 任何正方形尺寸-square2
– 边长为偶数的正方形-square4
(默认)– 边长可被 4 整除的正方形可以指定以下任意非空子集
-imageout <filename.*>
– 将图集位图保存为纯图像文件。格式与 -format
匹配-json <filename.json>
– 将图集的布局数据以及其他指标写入结构化的 JSON 文件-csv <filename.csv>
– 将字形布局数据写入简单的 CSV 文件-arfont <filename.arfont>
– 将图集及其布局数据保存为 Artery Font 文件-shadronpreview <filename.shadron> <sample text>
– 生成一个 Shadron 脚本,该脚本使用生成的图集绘制一个示例文本作为预览-size <EM size>
– 设置图集中字形的大小,单位为每 EM 像素-minsize <EM size>
– 设置最小大小。将使用适合相同图集尺寸的最大可能大小-emrange <EM range>
– 设置 EM 中距离场的范围-pxrange <pixel range>
(默认 = 2) – 设置输出像素中距离场的范围-angle <angle>
– 设置相邻边之间的最小角度,以被认为是角。附加 D 表示度数 (msdf
/ mtsdf
only)-coloringstrategy <simple / inktrap / distance>
– 选择边缘着色启发式方法 (msdf
/ mtsdf
only)-errorcorrection <mode>
– 选择错误校正算法。使用 help
作为模式以获取更多信息 (msdf
/ mtsdf
only)-miterlimit <value>
– 设置斜接限制,该限制限制了由于非常尖锐的角而导致的每个字形边界框的扩展 (psdf
/ msdf
/ mtsdf
only)-overlap
– 切换到支持重叠轮廓的距离场生成器-nopreprocess
– 禁用路径预处理,该预处理解决自相交和重叠轮廓-scanline
– 执行额外的扫描线过程来修复距离的符号-seed <N>
– 设置边缘着色启发式的初始种子-threads <N>
– 设置并行计算的线程数(0 = 自动)使用 -help
获取详尽的选项列表。
字符集文件是一个文本文件,使用 UTF-8 或 ASCII 编码。字符可以用以下方式表示
'A'
(UTF-8 编码),65
(十进制 Unicode),0x41
(十六进制 Unicode)['A', 'Z']
,[65, 90]
,[0x41, 0x5a]
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
(UTF-8 编码)条目应以逗号或空格分隔。在引号之间,反斜杠用作转义字符(例如 '\''
、'\\'
、"!\"#"
)。字符出现的顺序不予考虑。
此外,include 指令可用于包含其他字符集文件,并以分层方式组合字符集。它必须写在单独的一行上
@include "base-charset.txt"
字形集规范的语法与字符集的语法基本相同,但仅允许使用数值(十进制和十六进制)。
以下是注释的代码片段,演示了如何将该项目用作库。
#include <msdf-atlas-gen/msdf-atlas-gen.h>
using namespace msdf_atlas;
bool generateAtlas(const char *fontFilename) {
bool success = false;
// Initialize instance of FreeType library
if (msdfgen::FreetypeHandle *ft = msdfgen::initializeFreetype()) {
// Load font file
if (msdfgen::FontHandle *font = msdfgen::loadFont(ft, fontFilename)) {
// Storage for glyph geometry and their coordinates in the atlas
std::vector<GlyphGeometry> glyphs;
// FontGeometry is a helper class that loads a set of glyphs from a single font.
// It can also be used to get additional font metrics, kerning information, etc.
FontGeometry fontGeometry(&glyphs);
// Load a set of character glyphs:
// The second argument can be ignored unless you mix different font sizes in one atlas.
// In the last argument, you can specify a charset other than ASCII.
// To load specific glyph indices, use loadGlyphs instead.
fontGeometry.loadCharset(font, 1.0, Charset::ASCII);
// Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies.
const double maxCornerAngle = 3.0;
for (GlyphGeometry &glyph : glyphs)
glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0);
// TightAtlasPacker class computes the layout of the atlas.
TightAtlasPacker packer;
// Set atlas parameters:
// setDimensions or setDimensionsConstraint to find the best value
packer.setDimensionsConstraint(TightAtlasPacker::DimensionsConstraint::SQUARE);
// setScale for a fixed size or setMinimumScale to use the largest that fits
packer.setMinimumScale(24.0);
// setPixelRange or setUnitRange
packer.setPixelRange(2.0);
packer.setMiterLimit(1.0);
// Compute atlas layout - pack glyphs
packer.pack(glyphs.data(), glyphs.size());
// Get final atlas dimensions
int width = 0, height = 0;
packer.getDimensions(width, height);
// The ImmediateAtlasGenerator class facilitates the generation of the atlas bitmap.
ImmediateAtlasGenerator<
float, // pixel type of buffer for individual glyphs depends on generator function
3, // number of atlas color channels
&msdfGenerator, // function to generate bitmaps for individual glyphs
BitmapAtlasStorage<byte, 3> // class that stores the atlas bitmap
// For example, a custom atlas storage class that stores it in VRAM can be used.
> generator(width, height);
// GeneratorAttributes can be modified to change the generator's default settings.
GeneratorAttributes attributes;
generator.setAttributes(attributes);
generator.setThreadCount(4);
// Generate atlas bitmap
generator.generate(glyphs.data(), glyphs.size());
// The atlas bitmap can now be retrieved via atlasStorage as a BitmapConstRef.
// The glyphs array (or fontGeometry) contains positioning data for typesetting text.
success = myProject::submitAtlasBitmapAndLayout(generator.atlasStorage(), glyphs);
// Cleanup
msdfgen::destroyFont(font);
}
msdfgen::deinitializeFreetype(ft);
}
return success;
}
DynamicAtlas
类允许您在需要时“即时”将字形添加到图集中。在此示例中,ImmediateAtlasGenerator
用作底层图集生成器,但这并不是此目的的理想选择,因为它可能会每次都启动新线程。在实践中,您通常会定义自己的图集生成器类,该类可以正确处理您的特定性能和同步要求。
获取 GlyphGeometry
对象可以从前面的示例进行调整。
#include <msdf-atlas-gen/msdf-atlas-gen.h>
using namespace msdf_atlas;
using MyDynamicAtlas = DynamicAtlas<ImmediateAtlasGenerator<float, 3, &msdfGenerator, BitmapAtlasStorage<byte, 3>>>;
const double pixelRange = 2.0;
const double glyphScale = 32.0;
const double miterLimit = 1.0;
const double maxCornerAngle = 3.0;
MyDynamicAtlas atlas;
void addGlyphsToAtlas(GlyphGeometry *glyphs, int count) {
for (int i = 0; i < count; ++i) {
// Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies.
glyphs[i].edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0);
// Finalize glyph box size based on the parameters
glyphs[i].wrapBox(glyphScale, pixelRange/glyphScale, miterLimit);
}
// Add glyphs to atlas - invokes the underlying atlas generator
// Adding multiple glyphs at once may improve packing efficiency.
MyDynamicAtlas::ChangeFlags change = atlas.add(glyphs, count);
if (change&MyDynamicAtlas::RESIZED) {
// Atlas has been enlarged - can be handled here or directly in custom generator class
}
// Glyph positioning data is now stored in glyphs.
}
可以作为 dynamicAtlas.atlasGenerator().atlasStorage()
访问图集存储(及其位图)。