2026-08-21 17:30:49 +00:00
2026-07-31 15:22:18 +08:00
2026-08-21 17:51:18 +08:00
2026-07-17 15:17:08 +08:00
2026-07-17 15:17:08 +08:00
2026-07-13 07:48:14 +00:00
2026-08-22 01:30:35 +08:00
2026-08-21 17:51:18 +08:00

timi-icon-font

纯 Java SVG 图标字体工具库,支持 SVG 构建 TTF,也支持从 TrueType glyf 字体导出 SVG 字形。

构建 TTF

List<IconGlyph> glyphs = List.of(
		IconGlyph.of("home", "e001", "M128 512L512 128L896 512L768 512L768 896L256 896L256 512Z")
);

byte[] ttf = IconFontBuilder.build("TimiIcon", glyphs);

也可以直接用 name -> pathData 映射并指定起始 Unicode

Map<String, String> paths = new LinkedHashMap<>();
paths.put("home", "M128 512L512 128L896 512L768 512L768 896L256 896L256 512Z");

byte[] ttf = IconFontBuilder.build("TimiIcon", paths, 0xE001);

从目录或 JSON 文件构建:

IconFontOptions options = IconFontOptions.defaults("TimiIcon");
IconFontIO.writeTtfFromSvgDirectory(Path.of("icons.ttf"), options, Path.of("icons"), 0xE001);
IconFontIO.writeTtfFromSvgJson(Path.of("icons.ttf"), options, Path.of("icons.json"), 0xE001);

如果源图标基于固定画布绘制,例如 16 x 16,但图形没有占满整个画布,应显式指定源画布,避免构建 TTF 时按字形外接框被二次放大:

IconFontOptions options = IconFontOptions.defaults("TimiIcon")
		.withSourceBounds(0, 0, 16, 16);

默认会保留源画布中的原始留白与落点,这对通用图标库更稳妥。如果希望某个方向按实际字形外接框居中,可单独开启:

IconFontOptions options = IconFontOptions.defaults("TimiIcon")
		.withSourceBounds(0, 0, 16, 16)
		.withAlignment(GlyphAlignment.SOURCE, GlyphAlignment.GLYPH_CENTER);

像素风图标如果希望尽量贴齐源网格,可额外启用偏移吸附。它会牺牲部分“数学居中”,换取更稳定的像素边缘:

IconFontOptions options = IconFontOptions.defaults("TimiIcon")
		.withSourceBounds(0, 0, 16, 16)
		.withAlignment(GlyphAlignment.SOURCE, GlyphAlignment.GLYPH_CENTER)
		.withSnapOffsetToGrid(true);

写入字体元数据

FontMetadata metadata = FontMetadata.defaults("TimiIcon");
metadata.setDesigner("Codex");
metadata.setCopyright("Copyright 2026 Timi");
metadata.setVersion("Version 1.000");
metadata.setLicense("Preview and print embedding only");
metadata.setLicenseUrl("https://example.com/license");
metadata.setEmbeddingRestrictions(FontEmbeddingRestrictions.of(
		FontEmbeddingRestrictions.PREVIEW_AND_PRINT
				| FontEmbeddingRestrictions.NO_SUBSETTING
));

IconFontOptions options = IconFontOptions.defaults("TimiIcon").withMetadata(metadata);
IconFont font = IconFontBuilder.buildFont(options, glyphs);

TTF 导出 SVG

List<SvgGlyph> glyphs = TtfIconFontReader.readSvgGlyphs(ttfBytes);
String svg = glyphs.getFirst().getSvg();

导出为目录或 JSON

IconFontIO.writeSvgDirectory(Path.of("icons.ttf"), Path.of("icons-out"));
IconFontIO.writeSvgJson(Path.of("icons.ttf"), Path.of("icons.json"));

CLI

打包后可通过可执行 jar 调用:

java -jar target/timi-icon-font-0.0.1-all.jar build \
  -i icons \
  -o icons.ttf \
  --family TimiIcon \
  --start-unicode e001 \
  --designer Codex \
  --fs-type 0x104

java -jar target/timi-icon-font-0.0.1-all.jar build \
  -i icons.json \
  -o icons.ttf \
  --input-format json \
  --horizontal-alignment source \
  --vertical-alignment glyph_center \
  --snap-offset-to-grid true \
  --source-width 16 \
  --source-height 16 \
  --metadata-json metadata.json

java -jar target/timi-icon-font-0.0.1-all.jar export \
  -i icons.ttf \
  -o icons-out

java -jar target/timi-icon-font-0.0.1-all.jar export \
  -i icons.ttf \
  -o icons.json \
  --output-format json

输入目录格式:*.svg 文件名作为图标名称,文件内容为 SVG path 或完整 SVG。

输入 JSON 格式:

{
  "home": "M128 512L512 128L896 512L768 512L768 896L256 896L256 512Z"
}

读取字体信息

FontInfo info = TtfIconFontReader.readFontInfo(ttfBytes);
FontMetadata metadata = info.metadata();
FontMetrics metrics = info.metrics();
List<CharacterMapping> characters = info.characters();

兼容范围

  • SVG path 支持 M/L/H/V/C/S/Q/T/A/Z 与相对命令,支持外层 XML、完整 SVG 和多个 path,曲线会按配置采样为 TrueType 简单轮廓。
  • TTF 导出支持 cmap format 4/12glyf 简单轮廓和常见复合字形。
  • 元数据支持 name 表常用字段、OS/2 fsType 使用限制、weight/width/vendor、字符映射和基础指标信息。
  • CFF/OpenType PS 轮廓不是 TrueType glyf 数据,当前会抛出明确异常。
S
Description
SVG 字体图标
Readme MIT
83 KiB
v0.0.3
Latest
2026-08-21 17:31:02 +00:00
Languages
Java 91.6%
HTML 8.4%