You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FontTools打包Primer/Octicons为WOFF字体并关联CSS类的实现问题求助

FontTools打包Primer/Octicons为WOFF字体并关联CSS类的实现问题求助

我最近一直在尝试把Primer/Octicons的所有SVG图标打包成单个WOFF字体文件,搭配CSS用Unicode字符引用每个图标,就像Bootstrap Icons那样——能通过<i class='oi oi-codepilot-16'></i>这种方式调用图标。目前我大概摸清楚了整体思路,但相关文档讲得不够细致,始终没法把WOFF文件里的SVG图标和Unicode字符成功绑定。

我原本的预期是做出和Bootstrap Icons一样的效果:所有SVG打包进单个WOFF,通过CSS类来调用。但每次尝试要么报错,要么最后生成的文件没法用。试过AI工具找方案也没解决,最后只能自己写Python脚本。

现在脚本已经能生成WOFF文件和对应的CSS,但放到Web环境测试后发现完全不行——每个图标都显示成未知的Unicode字符(类似方块占位符)。

我期望的HTML调用方式如下(希望保持这个写法):

<!--I WANT THIS TO STAY LIKE THIS-->
<i class='oi oi-codepilot-16'></i>

参考Bootstrap Icons修改的CSS代码:

/*this code ripped from bootstrap-icons.css, edited to include icons i want to use, and include the woff font the python program creates*/
@font-face {

    font-display:block;
    font-family:"octicons";
    src: url(./fonts/octicon.woff) format("woff");
}
.oi::before,
[class^="oi-"]::before,
[class*="oi-"]::before {
    display:inline-block;
    font-family: octicons !important;
    font-style: normal;
    font-weight: normal !important;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    vertical-align: -.125em;
    -webkit-font-smoothing: antialiased;
    -mos-osx-font-smoothing: grayscale
}
/*. . .*/
/*python generated code*/
.oi-copilot-16::before { content: "\f57481"; }

我自己编写的Python脚本:

import os
import json
import defcon
from fontTools.ttLib import TTFont, newTable,getTableClass as gtc ,getTableModule as gtm,identifierToTag as idt
from fontTools.ttLib.tables.DefaultTable import DefaultTable
from fontTools.svgLib.path import SVGPath as svgPath
#from fontTools.ttLib.woff import WOFFFlavor
from svgpathtools import svg2paths
import math
def svg_to_glyph(svg_file, glyph_name,glyph_unicode):
    paths, attributes = svg2paths(svg_file)
    glyph_code = ''
    
    for path in paths:
        glyph_code += f'<path d="{path.d()}" />'
    #unicode = math.round(math.random() * 10000)
    return  f'<glyph glyph-name="{glyph_name}" unicode="{glyph_unicode}" d="{glyph_code}" />'

def create_woff_font(svg_files, output_woff, output_json):
    jsn = {};
    font = TTFont()
    CmapSubtable = gtm("cmap").CmapSubtable
    cmap4_0_3 = CmapSubtable.newSubtable(4)
    cmap4_0_3.platformID = 0
    cmap4_0_3.platEncID = 3
    cmap4_0_3.language = 0
    cmap4_0_3.cmap = {};
    unicode = 0x0E000
    for file in svg_files:
        handle = open(file,"r")
        print(file)
        name = str(file).split("/")[::-1][0].replace(".svg","")

        #print(file.split("/").reverse())

        svg = handle.read()
        unicode+=1
        glyph = defcon.Glyph()
        path = svgPath.fromstring(svg)
        path.draw(glyph.getPen())
        cmap4_0_3.cmap[unicode] = glyph
        jsn[unicode] = name
        handle.close()
    cmap = newTable("cmap");
    cmap.tableVersion = 0;
    cmap.tables = [cmap4_0_3]
    font.cmap = cmap
    font.flavor = "woff"
    font.save(output_woff + ".woff")
    #font.flavor = "woff2"
    #font.save(output_woff + ".woff2")
    #json.dump(jsn,json_file, indent=4)
    with open(output_json, 'w') as json_file:
       json.dump(jsn, json_file, indent=4)
def create_css(output_css,jsn):
    csstxt = ""
    csstxt += """
@font-face {\n
    font-display:block;
    font-family:\"octicons\";
    src: url(./fonts/octicon.woff2) format("woff2"),
    url(./fonts/octicon.woff) format("woff");
}\n"""
    csstxt += """.oi::before,
[class^="oi-"]::before,
[class*="oi-"]::before {
    display:inline-block;
    font-family: octicons !important;
    font-style: normal;
    font-weight: normal !important;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    vertical-align: -.125em;
    -webkit-font-smoothing: antialiased;
    -mos-osx-font-smoothing: grayscale
}\n"""
    with open(output_json, "r") as jsn:
        m = jsn.read()
        jso = json.loads(m)
        for i in jso.items():
            csstxt += ".oi-"+str(i[1]) + "::before { content: \"\\f"+i[0] + "\"; }\n"
    handle = open(output_css,"w");handle.write(csstxt)
if __name__ == "__main__":
    svg_directory = './icons'
    output_woff = './css/octicon'
    output_json = './css/octicon-map.json'
    output_css = "./css/octicon.css"
    svg_files = [os.path.join(svg_directory, f) for f in os.listdir(svg_directory) if f.endswith('.svg')]
    create_woff_font(svg_files, output_woff, output_json)
    create_css(output_css,output_json)

备注:内容来源于stack exchange,提问作者The Heavy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 03:18:19