字体子集化实践探索

发布于:2024-12-18 ⋅ 阅读:(34) ⋅ 点赞:(0)

最近项目rust生成PDF组件printpdf需要内嵌完整字体导致生成的PDF很大,需要做压缩,但是rust的类库allsorts::subset::subset不支持windows,所以做了一些windows下字体子集化的尝试

方案一:node.js做子集化
fontmin 缺点是也需要集成node环境,很多网络下载的字体都不支持

方案二:python做子集化
fontTools库的subset工具,兼容性最好的子集化工具,参数也最丰富
缺点:需要软件集成mini python环境,在低端电脑执行速度特别慢
pip install fonttools
可以直接用命令行执行
pyftsubset 原始字体文件路径 --text=需要保留的字符 --output-file=输出子集字体文件路径
完整的参数使用查看源码

from fontTools.subset import subset
 
def create_font_subset(input_font, output_font, characters):
    subset_options = {'glyphs': characters}
    subset(input_font, output_font, subset_options)
 
input_font_path = 'path/to/input_font.ttf'
output_font_path = 'path/to/output_font.ttf'
characters_to_include = 'abcdefghijklmnopqrstuvwxyz'
 
create_font_subset(input_font_path, output_font_path, characters_to_include)

方案三:C#做子集化
Microsoft.Extensions.FontSubset 库

using System;
using System.IO;
using Microsoft.Extensions.FontSubset;

class Program
{
    static void Main(string[] args)
    {
        string fontPath = "path/to/font.ttf"; // 字体文件路径
        string[] characters = new string[] { "A", "B", "C" }; // 需要包含在子集中的字符列表
        string outputPath = "output.ttf"; // 输出文件路径

        using (FileStream outputStream = File.Create(outputPath))
        {
            FontSubset.BuildSubset(fontPath, characters, outputStream);
        }
    }
}

有一个fontsubset已经编译好可以直接用
fontsubset-console -c <字符集目录> -r <字符集文件匹配规则> -a -s <输入字体文件> <输出的字体文件>

方案四:java做子集化
拷贝了一个韩国人的项目,放到自己的仓库
启动一个java http服务,通过入参生成子集,第一次要400ms左右,后面执行越来越快几十ms
缺点:生成的字体仍然有1.3M;需要集成jre环境;放弃

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.FontSubsetGenerator;

import java.io.IOException;

public class SubFontByItextPdf {
    public static boolean subFont(String sourceFontFile, String destFontFile, String text) {
        long startTime = System.currentTimeMillis();
        try {
            String path = FontSubsetGenerator.GEN(sourceFontFile, destFontFile, text);
            System.out.println("result: "+path);
        } catch (DocumentException e) {
            e.printStackTrace();
            System.out.println("error");
            return false;
        } catch (IOException e) {
            System.out.println("error");
            e.printStackTrace();
            return false;
        }
        System.out.println("cost" + (System.currentTimeMillis() - startTime) + "ms");
        System.out.println("done");
        return true;
    }
}

方案五:用harfbuzz的工具类hb-subset
调用命令行直接执行,下载地址
hb-subset.exe --output-file=dest.otf C:\source.otf 你好呀
执行速度很快,字体子集化结果也比较理想
参数使用查看源码,也可以hb-subset.exe --help-all查看所有参数

hb-subset.exe --name-IDs=1,2 --layout-features=  --name-languages=* --desubroutinize --drop-tables=DSIG,hdmx,VDMX,LTSH,PCLT,vhea,vmtx,VORG,gasp --no-hinting --retain-gids --glyph-names --name-legacy --output-file=tmp.otf C:\Medium.otf 你好呀

最小依赖

hb-subset.exe
libglib-2.0-0.dll
libharfbuzz-0.dll
libharfbuzz-subset-0.dll
libpcre2-8.dll
libintl-8.dll

网站公告

今日签到

点亮在社区的每一天
去签到