Files
Timi fcf977766f
CI/CD / build-deploy (pull_request) Successful in 14s
v0.0.2
2026-08-21 17:51:18 +08:00

147 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# timi-icon-font
纯 Java SVG 图标字体工具库,支持 SVG 构建 TTF,也支持从 TrueType `glyf` 字体导出 SVG 字形。
## 构建 TTF
```java
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
```java
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 文件构建:
```java
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 时按字形外接框被二次放大:
```java
IconFontOptions options = IconFontOptions.defaults("TimiIcon")
.withSourceBounds(0, 0, 16, 16);
```
默认会保留源画布中的原始留白与落点,这对通用图标库更稳妥。如果希望某个方向按实际字形外接框居中,可单独开启:
```java
IconFontOptions options = IconFontOptions.defaults("TimiIcon")
.withSourceBounds(0, 0, 16, 16)
.withAlignment(GlyphAlignment.SOURCE, GlyphAlignment.GLYPH_CENTER);
```
像素风图标如果希望尽量贴齐源网格,可额外启用偏移吸附。它会牺牲部分“数学居中”,换取更稳定的像素边缘:
```java
IconFontOptions options = IconFontOptions.defaults("TimiIcon")
.withSourceBounds(0, 0, 16, 16)
.withAlignment(GlyphAlignment.SOURCE, GlyphAlignment.GLYPH_CENTER)
.withSnapOffsetToGrid(true);
```
## 写入字体元数据
```java
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
```java
List<SvgGlyph> glyphs = TtfIconFontReader.readSvgGlyphs(ttfBytes);
String svg = glyphs.getFirst().getSvg();
```
导出为目录或 JSON
```java
IconFontIO.writeSvgDirectory(Path.of("icons.ttf"), Path.of("icons-out"));
IconFontIO.writeSvgJson(Path.of("icons.ttf"), Path.of("icons.json"));
```
## CLI
打包后可通过可执行 jar 调用:
```shell
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 格式:
```json
{
"home": "M128 512L512 128L896 512L768 512L768 896L256 896L256 512Z"
}
```
## 读取字体信息
```java
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/12``glyf` 简单轮廓和常见复合字形。
- 元数据支持 `name` 表常用字段、`OS/2 fsType` 使用限制、weight/width/vendor、字符映射和基础指标信息。
- CFF/OpenType PS 轮廓不是 TrueType `glyf` 数据,当前会抛出明确异常。