# timi-icon-font 纯 Java SVG 图标字体工具库,支持 SVG 构建 TTF,也支持从 TrueType `glyf` 字体导出 SVG 字形。 ## 构建 TTF ```java List 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 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 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.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.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.jar export \ -i icons.ttf \ -o icons-out java -jar target/timi-icon-font-0.0.1.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 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` 数据,当前会抛出明确异常。