Repository navigation
Releases
find-font 1.0.1
find-font 1.0.1 —— 压缩包里现在只有一个 FindFont.exe。Windows 10 1803+ / Windows 11,绿色版免安装。
下载
| 文件 | 说明 |
|---|---|
find-font-1.0.1-win-x64.zip |
解压后双击 FindFont.exe |
解压出来就这一个文件(约 1 MB),没有第二个 exe、没有附带 dll、没有安装程序,也不会在开始菜单或注册表里留下东西。要卸载直接删掉它。
需要 .NET 8 桌面运行时(Desktop Runtime)。没装的话,Windows 会弹出系统对话框说明并给出下载链接,不会静默双击无反应。
1.0.1 改了什么
- 发布包从两个 exe 变成一个:原来是一个 28 KB 的 .NET Framework 引导器负责检查运行时、再启动 1 MB 的主程序,两个中文名一样的 exe 摆在一起,用户不知道该点哪个。现在主程序自己就是入口,程序集名
FindFont与图标、快捷方式、任务管理器里的名字一致。 build.cmd publish末尾会校验输出目录里除了FindFont.exe没有别的文件,CI 里也有同名测试盯着——省得以后不小心又冒出一个 exe 或 dll 没人发现。
完整能力
全字体离屏渲染预览 / 300 ms 防抖搜索与命中高亮 / 分类与四种排序 / 2–3 字体对比 / 拖放安装 / 多字面 .ttc 展开 / 字形缺失检测(区分「cmap 无映射」与「映射到空字形」)/ 可变字体坐标轴 / 嵌入许可位 / 装给当前用户(免 UAC)或所有用户 / 失效登记清理(不动字体文件)/ 单实例 / 记忆上次状态 / PerMonitorV2 DPI / 崩溃日志 / Mica 材质。
实现要点
- 全程离屏
FormattedText+RenderTargetBitmap出冻结位图,XAML 里不出现FontFamily绑定,规避 WPF 加载上千套字形的内存暴涨(1380 个字体约 160 MB)。 - 直读 sfnt 的
name/OS/2/head/cmap/loca/glyf/maxp/fvar表,0.2–0.4 ms/文件;不依赖GlyphTypeface(43 ms/文件)。 - 2–4 条 STA 渲染线程按缓存键分派,首屏 12 行冷渲染从 1.1 s 降到 150 ms。
VirtualizingStackPanel+ 位图 LRU(96 MB 字节预算,不是按条数)。
已知限制
- 旧式
.fon位图字体不是 sfnt 容器,以文件名做显示名(不标记为异常)。 .ttc/.otc按文件头声明的成员展开,未独立声明的隐藏字面取不到。- 字形缺失检测只认
glyf轮廓;真 CFF 轮廓的.otf只报「无映射」,不判断字形是否为空。 - 缺字检测的依据是当前样本文字这一小组码位,回答的是「我这串字能不能显示出来」,不是「这个字体完整吗」。
- 可变字体只读轴范围,不解析
STAT表,也不提供轴滑杆。 fsType许可位只做提示:字体说「禁止嵌入」时仍会装上并附一句提醒,是否可用取决于授权。
find-font 1.0.0
find-font 1.0.0 —— 第一个正式版。Windows 10 1803+ / Windows 11,绿色版免安装。
下载
| 文件 | 说明 |
|---|---|
find-font-1.0.0-win-x64.zip |
解压后双击 FindFont.exe |
需要 .NET 8 桌面运行时(Desktop Runtime)。没装的话引导器会弹框说明并给出下载链接,不会静默失败。
1.0.0 新增
- 可变字体坐标轴:读
fvar表,在右栏「档案」列出wght 100–900、wdth 75–100这类轴范围;静态字体不显示这一段。 - 嵌入许可位:读 OS/2
fsType,标出「禁止嵌入 / 仅可预览与打印 / 可安装(允许嵌入) / 仅位图嵌入」,并注明是否禁止子集化。修正了此前把 BitmapOnly 位误读成「仅可编辑嵌入」的错误。只提示不阻断,装不装由你和授权方定。 - 装给当前用户,不需要管理员权限:新增第二条安装路径,写
HKCU+%LOCALAPPDATA%\Microsoft\Windows\Fonts。左栏两个按钮分别对应「装给我 / 所有人」,卸载时按文件位置自动选对路径。 - 测试分层:用例按
unit/integration/ui标注,CI 先跑纯逻辑那层再跑全量;发布任务在windows-2022与windows-latest两档上并行,NuGet 包缓存跨运行复用。
完整能力
全字体离屏渲染预览 / 300 ms 防抖搜索与命中高亮 / 分类与四种排序 / 2–3 字体对比 / 拖放安装 / 多字面 .ttc 展开 / 字形缺失检测(区分「cmap 无映射」与「映射到空字形」)/ 失效登记清理(不动字体文件)/ 单实例 / 记忆上次状态 / PerMonitorV2 DPI / 崩溃日志 / Mica 材质。
实现要点
- 全程离屏
FormattedText+RenderTargetBitmap出冻结位图,XAML 里不出现FontFamily绑定,规避 WPF 加载上千套字形的内存暴涨(1380 个字体约 160 MB)。 - 直读 sfnt 的
name/OS/2/head/cmap/loca/glyf/maxp/fvar表,0.2–0.4 ms/文件;不依赖GlyphTypeface(43 ms/文件)。 - 2–4 条 STA 渲染线程按缓存键分派,首屏 12 行冷渲染从 1.1 s 降到 150 ms。
VirtualizingStackPanel+ 位图 LRU(96 MB 字节预算,不是按条数)。
已知限制
- 旧式
.fon位图字体不是 sfnt 容器,以文件名做显示名(不标记为异常)。 .ttc/.otc按文件头声明的成员展开,未独立声明的隐藏字面取不到。- 字形缺失检测只认
glyf轮廓;真 CFF 轮廓的.otf只报「无映射」,不判断字形是否为空。 - 缺字检测的依据是当前样本文字这一小组码位,回答的是「我这串字能不能显示出来」,不是「这个字体完整吗」。
- 可变字体只读轴范围,不解析
STAT表,也不提供轴滑杆。
find-font v0.9.0-alpha-2
这一版只改界面细节,不动字体引擎。
改了什么
下拉框收进同一套纸张语言。 之前字号与排序两个下拉框用的是系统默认模板,灰渐变箭头、直角、和其它控件不是一家人。现在它们和输入框是同一张纸:1px 发丝边、2px 圆角、右侧一枚细 chevron;展开时底边从中心长出一条 2px 品红标尺,展开项也用同一套「2px 品红标尺 + 浅底」标记当前选中项,悬停与选中只动 Opacity。
「只显示」多了一项「正常」。 之前只能筛出有问题的字体,反过来想确认「这个字体在当前样本下是好的」只能一条条看。现在「失效 / 缺映射 / 空字形 / 正常」四项各自收窄一类;「正常」只留检测过且当前样本串下确实一字不缺的字体——没检测过的不算正常,因为「不知道」不等于「没问题」。
已知限制
- 「正常」只在当前样本文字这一小组码位上成立,不是整张字符表
- CFF 轮廓没有
loca表,只报「缺映射」,不判「空字形」
需要 .NET 8 桌面运行时;没装的话引导器会弹框说明并给出下载链接。
find-font v0.9.0-alpha
界面上这一轮做的是「收束」:不是加东西,是把已经加了太多的强调撤回去。
下载
| 文件 | 说明 |
|---|---|
find-font-0.9.0-alpha-win-x64.zip |
解压后双击 FindFont.exe |
需要 .NET 8 桌面运行时;没装的话引导器会弹框说明并给出下载链接。
这一版改了什么
- 品红只作校样标记。以前缺字、面数、失效都铺一层粉色药丸,屏幕上到处是强调色,等于什么都不强调。现在品红只出现在两处:选中瓦片左侧那条 2px 裁切线,和缺字示例里具体的几个字。面数改成安静灰字,失效改成暖褐文字。
- 间距落到 4px 网格。版心 24、栏内 16、段间 16、行距 4,索引栏所有内容从 x=16 起算,图标槽统一 16px,七个动作的标签因此自动对齐成一列。
- 索引栏换成图标化按钮。8 个 16px 线图标,动作区两列并排;状态栏钉在底部,滚动区和动作区不再互相挤压。
- 左栏拆成四段:分类 / 字重 / 只显示 / 排序。原来「风格 · 范围」混成一组,七个开关在 208px 宽里被裁掉一半。
- 标题字体换成 Constantia(
Constantia, Georgia, Cambria, serif)。Cambria 的对比度在 24px 标题上偏软,Constantia 更收敛,衬线只在标题出现一次。 - 文案去掉括注与自造术语。「样本文字(应用到全部样本)」→「样本文字」,「0 个失效登记」→「0 处失效」,状态栏从三行长句收成一行。
- 对比度修到 WCAG AA。
InkFaint从#8F959D提到#646A72,InkMuted提到#4E545C,两档灰在新底色上都过 4.5:1。 - 缺字示例优先给汉字。之前
日文毛笔字体.ttf那一行显示缺字:Thequickbrow——它缺的是一堆 ASCII,但这类字体本来就只用来排中文。现在先挑东亚字符,显示的是缺字:你,。 - 索引栏与档案面板拆成模板(
Themes/Rail.xaml、Themes/Colophon.xaml),MainWindow.xaml只留三栏骨架。
三条新的护栏
测试从 52 项加到 55 项,新增的都是「界面会悄悄退化」的地方:
- 间距必须落在 4px 网格上,且版心台阶单调(标题 > 面板标题 > 正文 > 元信息)
- 五种前景色在三种底色上的对比度都 ≥4.5:1
- 样本行模板里
ProofWash出现次数必须为 0(品红不许再做药丸底色)
已知限制
- 缺字检测只认
glyf轮廓;CFF 字体(部分.otf)只报「无映射」 - 检测依据是当前样本文字那一小组码位,不是整张字符表
- 旧式
.fon位图字体以文件名显示 - 语言归属优先用 OS/2 的
ulUnicodeRange,表里没写时才回落关键词推断
find-font v0.8.0-alpha
三栏还在,但字体列表改成多列瓦片网格了:1360×880 的窗口里横向排 3 个字体,每个瓦片宽 ~340px,一屏能看到 9 个而不是 3 个。
这一版改了什么
| 之前 | 现在 |
|---|---|
| 1600×1000,索引栏 272px,档案栏 380px | 1360×880,索引栏 208px,档案栏 300px |
| 单列样本行,一行一个字体 | 1–3 列瓦片网格,列数按列表实际可用宽度收敛 |
| 选中行高度从 92px 动画到 220px | 瓦片不做高度动画,选中只抬底色 + 左侧 2px 品红竖条 |
| 正文 14px / 标题 26px | 正文 15px / 标题 24px |
| 索引栏塞进一个滚动区,动作区挤在下方 | 分类固定、风格开关固定、动作区独立滚动、状态栏钉底部 |
窗口缩到 1080 宽仍是两列;展开右侧「档案」栏时列表自动退回两列,而不是把第三列挤出可视区。
顺手修掉的两个 bug
- 瓦片永久卡在「正在渲染…」:渲染缓存原来会按请求序号丢弃旧请求,被取消的那张图永远回不到界面。改列宽、改预览字号、改 DPI 都会触发,表现为大片空白。现在只尊重调用方显式传入的取消令牌,重复渲染交给在途去重。
- 右栏展开后第三列被裁:列数按窗口宽算、瓦片宽按列表宽算,两套尺子。现在统一用列表实际可用宽度,并把瓦片宽向下量化到 32px 桶——拖窗口只在跨桶时重渲染一次。
下载
解压后双击 FindFont.exe。需要 .NET 8 桌面运行时;没装的话引导器会弹框给出下载链接。
已知限制
沿用 0.7.0:语言归属优先读 ulUnicodeRange,缺失时才回落名字关键词;.ttc 的多字面靠文件头偏移枚举,头部没声明的隐藏字面取不到;字形缺失检测只认 glyf 轮廓,CFF 字体只报无映射;检测依据是当前样本文字这一小组码位,不是整张字符表。
find-font v0.7.0-alpha
这版加的是「为什么有些字显示成空白」的答案。
下载
| 文件 | 说明 |
|---|---|
find-font-0.7.0-alpha-win-x64.zip |
解压后双击 FindFont.exe,需要 .NET 8 桌面运行时 |
新功能:字形缺失检测
以前只能看到「这一行有空白」,但空白有两种完全不同的成因,修法也不一样:
| 情况 | 现象 | 真实原因 |
|---|---|---|
| 无映射 | 某个字的位置是空白 | cmap 里根本没有这个码位,字体不知道自己该画什么 |
| 空字形 | 大片汉字都是空白 | cmap 里有映射,但 glyf 里那个字形是空的 —— 字体拿占位符凑数 |
现在每个字体在样本文字下都会核对一遍,列表里出现「缺字 21/24」这样的徽标,下面一行列出到底缺了哪几个字:
- 左栏新增两个开关:只看缺映射 / 只看空字形,互不混淆
- 右栏「档案」里给出细分数值与完整缺字清单
- 改样本文字后自动重新检测(300 ms 防抖),探测集相同则直接命中缓存
实测本机 1380 个字体、24 个不同码位:约 140 ms 跑完,命中缓存约 1 ms,其中 518 个字体在默认样本下有缺字。
实现要点
- 直读
cmap(支持 fmt 0/4/6/12,按平台与 format 打分挑最佳子表)+loca/glyf定向随机读,不整表解析 —— 全部cmap表加起来 48 MB,整读完全不可接受 - 空字形的判据是
loca[gid+1] - loca[gid] == 0,叠加glyf开头的numberOfContours == 0;负数表示复合字形,有轮廓 - 真 CFF 轮廓(只有
CFF表、没有loca的.otf)不猜空字形,只报无映射并显式标注「轮廓格式不支持空字形检测」 —— 启发式判断在实测里误差太大 - 检测跑在扫描之后的并行任务里,首屏不等它;结果按(路径、字面、探测集)缓存
顺带的修正
.otf后缀不等于 CFF:Noto Sans SC (TrueType).otf是 TrueType 轮廓,照常判空字形- 测试从 42 项增到 49 项,新增 7 项都用本机真实坏字体验证(
流丽行书.ttf的无映射、日文毛笔字体.ttf的空字形)
find-font v0.6.0-alpha
本次发布把「双击到看见第一屏字体」这条链路重做了一遍。
这次为什么算快
| 环节 | 之前 | 现在 |
|---|---|---|
| 扫描出完整列表 | 约 1.2 s | 约 0.4 s |
| 全量元数据解析 | 453 ms(每文件读两遍头) | 270 ms(每文件只打开一次) |
| 首屏 12 行出图 | 1062–1137 ms(单线程序列) | 约 150 ms(2–4 条渲染线程并发) |
关键在于三处改动,都不是「调参」级别的微调:
- 每个字体文件只打开一次。以前为了展开
.ttc里的多字面,同一个文件要读两遍文件头,再单独new FileInfo拿大小和时间——三次系统调用。现在一次FileStream把头、字面表、大小、修改时间全部带回来。 - 扫描按文件并行。注册表四个视图(HKLM/HKCU × 32/64)并行读,结果按固定视图顺序拼接,保证输出可复现;
ResolvePath的结果按注册表值缓存,2560 条注册表项里的重名路径不再反复File.Exists。 - 渲染从单线程改成线程池。
RenderTargetBitmap要求 STA,所以开了 2–4 条各自带 Dispatcher 的 STA 线程,按缓存键哈希分派——同一个字体永远落同一条线程,避免Typeface跨线程使用。首屏十几行的请求一次性全投出去,UI 一张都不等。
另外还有:首屏入场动画从 260 ms 缩到 80 ms(它不是在装饰,是在强迫用户等);DPI 在窗口构造后就上报,早于任何渲染请求,避免首屏按 96 DPI 出图再被拉伸模糊;发布配置打开 ReadyToRun 并关掉单文件压缩,跳过首次解包的冷 JIT;引导器的运行时检测结果会缓存,dotnet --list-runtimes 不再每次都拉起主机进程。
能自己看
「关于 / 环境信息」窗口底部现在会列出这一次启动的每一段耗时(从进程启动算起的绝对毫秒和增量),日志里也写一份。觉得哪里慢,把那段文字贴到 issue 里就行。
功能没变
1380 个字体、ttc 多字面展开、ulUnicodeRange 判语言、四种排序、命中高亮、拖放安装、一键安装卸载、失效登记清理——都和 0.5.0 一致。
已知限制
- 首次启动(ReadyToRun 缓存未热、系统文件缓存为空)明显慢于后续启动。
- 主程序依赖 .NET 8 桌面运行时;缺失时引导器会弹框说明并给出下载链接。
v0.5.0-alpha
第三个可用版本。Windows 10 1803+ / Windows 11,绿色版免安装。
下载
| 文件 | 说明 |
|---|---|
find-font-0.5.0-alpha-win-x64.zip |
解压后双击 FindFont.exe |
需要 .NET 8 桌面运行时(Desktop Runtime)。没装的话引导器会弹框说明并给出下载链接,不会静默失败。
这一版改了什么
字体集合不再只看到一个成员。 .ttc/.otc 一个文件里装着多个字面,以前只读第一个 —— simsun.ttc 只有宋体、新宋体整个丢掉。现在按文件头声明的成员逐个展开,本机 23 个容器解出 70 个字体,字体总数 1333 → 1380,中文分类 880 → 928,每条标出「第 2/3 面」。
语言归属改用字符覆盖位。 读 OS/2 的 ulUnicodeRange1-4:有汉字无假名判中文、有假名无汉字判日文、有韩文音节判韩文。同时覆盖汉字与假名的字体(SimSun 就是)不硬判,避免把中文字体标成日文。读不到这张表才回落到名字关键词。
排序: 按名称 / 按最近修改 / 按文件大小 / 按语言,四档都带名称兜底,所以结果可复现。排序方式记进设置。
命中高亮: 搜索结果的元数据行下方单独一行,命中片段用品格红加下划线标出 —— 一眼看出这个字体为什么被搜出来。
拖放安装: 把字体文件拖到窗口任意位置即可安装。拖拽悬停时光标就按「有没有能装的格式」切换,装不了的文件会说明原因而不是静默忽略。这与文件对话框走同一条分拣路径。
嵌入权限: 右栏档案新增「嵌入权限」,把 fsType 位翻译成「无嵌入限制 / 仅可预览与打印 / 禁止嵌入」等文案。
实现要点
- 全程离屏
FormattedText+RenderTargetBitmap出冻结位图,XAML 里不出现FontFamily绑定 —— 规避 WPF 加载上千套字形导致的内存暴涨(实测 1380 个字体约 160 MB) - 直读 sfnt 的
name/OS/2/head表,0.32 ms/文件;不依赖GlyphTypeface(43 ms/文件) - 多字面渲染用「文件 URI + #家族名」定位成员,否则同一个 .ttc 里所有行都会渲染成第一个成员
VirtualizingStackPanel+ 回收,图片走带字节预算(96 MB)的 LRU;只有被选中的行才渲染 220px 大样本- 主程序普通权限,安装/卸载走 runas 微进程;卸载只删本工具装过的文件(进回收站),系统字体只清登记
已知限制
- 多字面容器按文件头声明的成员展开;文件头里没独立声明的隐藏字面仍取不到
- 个别字体没写
ulUnicodeRange表,此时回落到名字关键词推断,冷门字体可能落进「其他」 - 旧式
.fon位图字体不是 sfnt 容器,以文件名做显示名(不标记为异常) - 只扫描
HKLM/HKCU下的标准字体注册表项 - 可变字体只显示默认实例,暂不提供轴调节
find-font v0.4.0-alpha
第四个预览版本。这一版把「用起来会硌手」的地方逐个补齐:重复双击不再开出两个窗口,窗口位置和上次搜索词会记住,高分屏样本不再发虚,崩了也有日志可查。同时把 7 个超过 300 行的源文件全部拆开。
下载
| 文件 | 说明 |
|---|---|
find-font-0.4.0-alpha-win-x64.zip |
解压后双击 FindFont.exe |
需要 .NET 8 桌面运行时。没装的话引导器会弹框说明并给出链接,不会静默失败。
这一版新增
- 单实例:再次双击只把已有窗口叫到前台,不会出现两个窗口各自扫一遍注册表。遇到拿不到互斥体的受限环境会降级为允许启动,不会让程序打不开。
- 记住上次状态:窗口位置 / 大小 / 是否最大化、上次搜索词、样本文字、字号、分类、风格全部存进
settings.json(%LOCALAPPDATA%下的find-font目录)。写入先落.tmp再原子替换,断电不会留下半截 JSON。拔掉第二块显示器后窗口不会恢复到屏幕外。 - 高分屏清晰:
app.manifest声明 PerMonitorV2,位图按监视器真实 DPI 渲染,DPI 参与缓存键,把窗口拖到另一块屏不会命中旧 DPI 的模糊图。 - 崩溃日志:未处理异常自动落盘,保留 7 天;
%LOCALAPPDATA%不可写时依次退到%TEMP%。左栏底部新增「关于 / 环境信息」,一键复制版本、OS build、运行时、字体数量、材质是否生效;状态栏下方新增「打开日志」。 - 源文件全部 ≤300 行:
MainViewModel、FontRenderCache、FontInstaller、FontScanner、FontMetadataReader、Themes/Controls.xaml、冒烟测试全部拆分,CI 里加了同名行数检查。
仍未做(留给 0.5.0)
搜索命中高亮、排序切换、拖放安装、.ttc 多成员展开、用 ulUnicodeRange 精确判语言。
已知限制
- 语言归属靠名字关键词推断,不解析字符表,冷门字体会归到「其他」
- 旧式
.fon位图字体不是 sfnt 容器,以文件名做显示名 .ttc/.otc只读第一个字体成员- 只扫描
HKLM/HKCU下的标准字体注册表项
find-font v0.3.0-alpha
候选版本。Windows 10 1803+ / Windows 11,绿色版免安装。
下载
| 文件 | 说明 |
|---|---|
find-font-0.3.0-alpha-win-x64.zip |
解压后双击 FindFont.exe |
需要 .NET 8 桌面运行时(Desktop Runtime)。没装的话引导器会弹框说明并给出下载链接,不会静默失败。
这一版修了什么
前两版有三个会伤到用户系统的缺陷,这个版本全部修掉:
- 卸载不再删除系统字体。 以前选中任意字体点卸载都会把文件删掉,包括 Arial 这种系统自带的。现在维护一份「本工具装过什么」的台账(
%ProgramData%\find-font\installed.txt),只有台账里的文件才删,而且走回收站;系统自带字体只清除注册表登记,确认框会提前写清是哪一种。 - 网页字体明确拒装。
.woff/.woff2/.eot是浏览器格式,装进C:\Windows\Fonts系统根本不认,以前会制造「装了但看不见」的假成功。现在在碰系统目录之前就拒绝,并说明原因和该转成什么格式。 - 注册表不再写重复项。 以前同一个字体登记两条值(裸名 + 带类型名),现在幂等:已存在指向同名文件的值就跳过,值名统一为
名字 (TrueType|OpenType|TrueType collection)。
另外补上了应用图标(16–256 七档),发布包里不再带 70 KB 的 pdb。
功能
- 全字体预览:把本机所有字体按真实字形渲染成缩略图,中英文混排可见
- 实时搜索:300 ms 防抖,匹配显示名 / 本地化名 / 中文名 / 家族名 / 文件名 / 样式名
- 筛选:中文 / 西文 / 其他 + 常规 / 粗体 / 斜体 + 只看失效登记
- 多字体对比:Ctrl 多选 1–3 个字体同屏对照,改文字实时重渲染
- 安装 / 卸载:走 UAC 提权微进程,取消提权不会留下半成品
- 失效登记清理:删掉注册表里指向缺失文件的僵尸条目,不动任何字体文件
实现要点
- 全程离屏
FormattedText+RenderTargetBitmap出冻结位图,XAML 里不出现FontFamily绑定 —— 规避 WPF 加载上千套字形导致的内存暴涨(1333 个字体约 160 MB) - 直读 sfnt 的
name/OS/2/head表补全家族名与字重,0.33 ms/文件;不依赖GlyphTypeface(43 ms/文件) VirtualizingStackPanel+VirtualizationMode=Recycling;只有被选中的行才渲染 220px 大样本,位图缓存按 96 MB 字节预算淘汰
已知限制
- 语言归属靠名字关键词推断,不解析字符表,冷门字体会归到「其他」
- 旧式
.fon位图字体不是 sfnt 容器,以文件名做显示名 .ttc/.otc只读第一个字体成员- 只扫描
HKLM/HKCU下的标准字体注册表项 - 卸载保护依赖台账:本版之前安装的字体没有台账记录,卸载时只会清登记、不会删文件(保守方向)