当前位置: 首页 > news >正文

字体子集化实践探索

最近项目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 subsetdef 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查看所有参数

相关文章:

字体子集化实践探索

最近项目rust生成PDF组件printpdf需要内嵌完整字体导致生成的PDF很大&#xff0c;需要做压缩&#xff0c;但是rust的类库allsorts::subset::subset不支持windows&#xff0c;所以做了一些windows下字体子集化的尝试 方案一&#xff1a;node.js做子集化 fontmin 缺点是也需要集…...

A1017 基于Java+JSP+SQL Server+servlet的二手购物平台的设计与实现

二手购物平台 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 摘 要 计算机以及网络技术的飞速发展&#xff0c;网络的应用在全国乃至全球日益普及&#xff0c;随着人们的思想水平和生活水平的提高&#xff0c;网络已经是人们必不可少的一部分。人们的…...

Simdroid-EC:液冷仿真新星,助力新能源汽车电机控制器高效散热

近年来&#xff0c;新能源电动车的销量呈现出快速增长的态势。据统计&#xff0c;2024 年1-10月中国新能源汽车销量达728万辆&#xff0c;同比增长37.8%。 电机控制器在新能源汽车中对于保障动力和安全性能扮演着至关重要的角色&#xff0c;其核心部件IGBT&#xff08;绝缘栅双…...

C语言——实现并求出两个数的最大公约数

问题描述&#xff1a;求出两个数的最大公约数 //求两个数的最大公约数 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<time.h>int main() {int a,b;printf("请您输入两个数 a 和 b\n");scanf…...

今天你学C++了吗?——C++中的类与对象(日期类的实现)——实践与知识的碰撞❤

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...

享元模式的理解和实践

在软件开发中&#xff0c;性能优化是一个永恒的话题。在追求高性能的过程中&#xff0c;减少内存的使用是一项重要的任务。享元模式&#xff08;Flyweight Pattern&#xff09;就是一种用于减少内存使用量的设计模式&#xff0c;它特别适用于存在大量重复对象的场景。本文将详细…...

Unreal Engine 中的UI界面开发

推荐的使用方式 轻量级 HUD:使用 Canvas 绘制简单的文本、调试信息或基础 UI(如准星、血量条等)。 复杂 UI:使用 UMG(Unreal Motion Graphics)和 Slate 进行布局和交互,避免手动管理 Canvas 绘制。 避免遮挡场景:仅绘制必要的内容,并利用透明度(如 FLinearColor(1, 1…...

Docker在Ubuntu和CentOS系统下的安装

目录 1. 各版本平台支持情况2. 在Ubuntu系统下安装docker3. 常见报错4. Docker的镜像源修改5. Docker目录修改6. 在CentOS系统下安装docker 1. 各版本平台支持情况 &#xff08;1&#xff09;平台支持情况如下&#xff1a; Server 版本 桌面版本 2. 在Ubuntu系统下安装docker…...

EXCEL 关于plot 折线图--频度折线图的一些细节

目录 0 折线图有很多 1 频度折线图 1.1 直接用原始数据做的频度折线图 2 将原始数据生成数据透视表 3 这样可以做出了&#xff0c;频度plot 4 做按某字段汇总&#xff0c;成为累计plot分布 5 修改上面显示效果&#xff0c;做成百分比累计plot频度分布 0 折线图有很多 这…...

Hive操作案例

目录 idea/dg远程连接导入数据建表数据导入 idea/dg远程连接 hive的详细安装不多展示&#xff0c;自行搜索即可。 依次启动zookeeper&#xff0c;hadoop 在zookeeper的节点上启动如下指令&#xff08;我的是1个主节点和2个备用节点&#xff09; 启动Hive的metastore&#xff0…...

C++ 内存管理和模板与STL

此篇目是之后各种C库的基础 目录 内存管理 内存分布 内存管理方式 new和delete operator new 与 operator delete函数 实现原理 定位new表达式(placement-new) 模板基础 泛型编程 模板 函数模板 类模板 STL 组成部分 内存管理 内存分布 int globalVar 1; //全局变量 静…...

JDK8新特性:Stream

JDK8最大的改变&#xff1a; 1. lambda表达式 2. Stream 1. Steam流的入门 什么是Stream&#xff1f; 也叫Stream流&#xff0c;是jdk8开始的一套API&#xff0c;用于操作集合或者数组中的数据 优点&#xff1a; Stream流大量结合了Lambda的语法风格来创建&#xff0c;提…...

前端传入Grule,后端保存到 .grl 文件中

前端传入Grule&#xff0c;后端保存到 .grl 文件中 通过简单的输入框&#xff0c;将Grule的部分拆解成 规则名称 规则描述 规则优先级 规则条件 规则逻辑Grule关键字 when Then 模拟了 if 判断的条件和逻辑部分 类似于 shell 和 ruby 之类的脚本语言&#xff0c;有 then 关键字…...

探索《Crypto Rumble》 游戏:经济模型篇

《Crypto Rumble》是一款基于 Zypher Network 游戏引擎打造的卡牌 RPG三消品类的 Web3 游戏&#xff0c;通过引人入胜的游戏设计以及轻量化的游戏玩法&#xff0c;《Crypto Rumble》不仅能够为玩家带来引人入胜的沉浸式游戏体验&#xff0c;同时基于 AI Bot 的游戏编辑器&#…...

【CSS in Depth 2 精译_072】第 12 章 CSS 排版与间距概述 + 12.1 间距设置(上):究竟该用 em 还是 px

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 ✔️ 12.1.1 使用 em 还是 px ✔️12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 文章目录 第 12 章 排版与间距…...

Elasticsearch对象映射

Spring Data Elasticsearch对象映射是将Java对象&#xff08;域实体&#xff09;映射到存储在Elasticsearchs中的JSON表示形式并返回的过程。内部用于此映射的类是MappingElasticsearchConverter。 元模型对象映射 基于元模型的方法使用域类型信息对Elasticsearch进行读写操作…...

Oracle 19c rac 补丁升级,从19.7 to19.22-集群

1. 补丁包概述 数据库环境 角色 数据库 IP地址 数据库版本 主机名 数据库名称 源端 RAC 172.30.21.166/167 19.7 hfcwdb66/hfcwdb67 hfdb 将以下补丁包上传到/soft下 上传到两个节点的soft目录下&#xff1a;p6880880_190000_Linux-x86-64.zip &#xff08;更新o…...

机器学习--Kaggle的使用

机器学习–Kaggle的使用 打开Kaggle: Your Machine Learning and Data Science Community并点击Sign In登录账号 kaggle中自带了很多的数据集 在点击Datasets之后&#xff0c;单点Notebook&#xff0c;如果有适用的数据集可以单击Copy and Edit复制其Notebook&#xff0c;之后…...

客户服务新突破,天润融通助力电动车企业实现数智化转型

近年来&#xff0c;两轮电动车成为年轻人喜爱的出行新方式&#xff0c;借着这种潮流&#xff0c;许多新兴品牌迅速发展&#xff0c;并跻身行业头部。 但问题也随之而来&#xff0c;由于业务快速发展&#xff0c;各类服务问题也开始增多。 比如天润融通服务的一家头部两轮电动…...

力扣题目 - 2931.购买物品的最大开销

题目 还需要你前往力扣官网查看详细的题目要求 地址 思路 这边需要你去力扣官网详细查看题目看了题目提供的示例 已经有了解法, 先把values转成1维数组,排序之后进行累加即可 代码 var maxSpending function (values) {let list values.flat();list.sort((a, b) > a - …...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)

目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 ​编辑​编辑 UDP的特征 socke函数 bind函数 recvfrom函数&#xff08;接收函数&#xff09; sendto函数&#xff08;发送函数&#xff09; 五、网络编程之 UDP 用…...

ThreadLocal 源码

ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物&#xff0c;因为每个访问一个线程局部变量的线程&#xff08;通过其 get 或 set 方法&#xff09;都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段&#xff0c;这些类希望将…...

Linux-进程间的通信

1、IPC&#xff1a; Inter Process Communication&#xff08;进程间通信&#xff09;&#xff1a; 由于每个进程在操作系统中有独立的地址空间&#xff0c;它们不能像线程那样直接访问彼此的内存&#xff0c;所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...