现在有一个半成品可用 https://github.com/congyu711/KaTeX
Fira Math这字体很不错, 想要在KaTeX中使用它.
有用的链接:
- https://yingtongli.me/blog/2022/09/24/katex-custom-fonts.html – alphanumeric text only
- https://github.com/KaTeX/KaTeX/discussions/3716
- https://github.com/firamath/firamath.github.io/blob/master/bibliography.md
- https://learn.microsoft.com/en-us/typography/opentype/spec/math
1 字体部分如何工作?
关于fonts和metrics有关的东西首先要看dockers/fonts/
.
看起来 fonts/
里面的字体是从docker中安装的texlive的computer
modern fonts提取的. 然后dockers/fonts/buildMetrics.sh
调用
src/metrics
里面的代码,直接从有关的tfm文件里读一些metric信息.
(我猜)生成的ttf,woff2等字体是保存 unicode -> (字形+一些信息)
这个映射关系的文件. src/metrics/mapping.pl
就是从tex
math到unicode的映射. 做完这个输出这样的东西
{
...
"AMS-Regular": {
"65": {
"char": 65,
"yshift": 0,
"xshift": 0,
"font": "msbm10"
},
...
之后输入到src/metrics/extract_tfms.py
得到
{
"AMS-Regular": {
"65": {
"depth": 0.0,
"height": 0.68889,
"italic": 0.0,
"skew": 0.0,
"width": 0.72222
},
...
最后会再做点工作然后把json塞入src/fontMetricsData.js
.
我猜如果成功的把Fira Math的metric弄到这个js文件里,
接下来改改css里的字体然后rebuild就行了.
采集metric和生成fonts的过程是独立的, 所以看起来大部分东西都是可以复用的.
2 Plan
- 由于本身字体分成很多小文件, 首先我也把 Fira Math 分成小文件
- 然后想办法搞到正确的
src/metrics/mapping.pl
for Fira Math - 最后改改css或者先rebuild再改css之类的.
在与 Fira Math 的作者交流之后意识到:
- 在 1. 中把Fira Math 像computer modern一样分成小文件可能可以避免让我需要修改大量KaTeX代码. KaTeX这样做是因为cm在TeX中是Type 1 font, 单个文件只能容纳256字符.
- Fira Math是Open
Type font. glyph id 到对应字符的 unicode
码位的映射已经包含在了字体的cmap表中. KaTeX生成的html里是unicode字符,
所以我不需要为Fira Math修改
src/metrics/mapping.pl
, 但是仍然需要对应的src/fontMetricsData.js
.
3 Extract fonts
KaTeX把\mathbb{A} \mathcal{B}
等等符号全部映射到普通拉丁字母A,B上, 这就导致需要在映射的时候做点工作.
而且另一个问题是KaTeX_AMS-Regular等字体在使用 unicode private use
area表示一些unicode中缺少的符号,
比如src/fonts/makeFF
中有这样的代码
0x0A => 0xE010, # \nleqslant
0x0B => 0xE00F, # \ngeqslant
因为这些不是我会用的符号, 我决定先不管它.
KaTeX_Main-Regular, KaTeX_Math-Italic.ttf 这些字体表现比较正常,
基本都是Fira Math的子集, 用这里的代码转换.
对于KaTeX_AMS-Regular和KaTeX_Size{k} 这些字体就需要单独处理,
我决定下载fontforge手动处理. Caligraphic 和 Fraktur 字体Fira
Math中也没有覆盖, Fira Math 本来就是sans serif字体,
所以我觉得其他字体都可直接用KaTeX版本.
3.1 Italic
看起来Fira Math字体并无斜体, 查了查貌似TeX是通过OpenType MATH
table来实现斜体, 我需要想想如何搞到Fira Math的斜体版本… 原来Fira
Math是有斜体的,
用fontforge修改比手写unicode映射要简单点(目前只有常用符号做了修改,
很多东西不能正常工作) KaTeX的很多设计让人疑惑,
为什么不做像unicode-math一样的设计, 把所有东西映射到正确的unicode上呢?
又比如, KaTeX的做法是把一个和一个类似的东西组合起来,
而且在字体中这个像的字符被映射到了private use
area.
Fira Math specimen 有点老旧, 实际上其中很多missing glyph现在已经补上了. Texlive里的firamath-regular.otf貌似也是旧版本, 比如缺少(0x2216 ∖)
事实上从 KaTeX 的commit history能看到字体主要是ylemkimon的工作. 我发邮件问了问他这些问题, 没有得到回复. 不过我看到这个知乎回答之后觉得映射问题可能是为了兼容screen reader? 不过我不觉得这样做就能让screen reader正确读出公式. 另外要谢谢曾祥东老师, 他是Fira Math的主要作者, 读博客和介绍FiraMath的知乎回答都让我学到很多东西.
如果只是更换字体的话, 很多东西看起来有点奇怪
[commit 866527 to commit ____] 这个blog在使用这个版本的firamath katex.

但是我觉得最常用的LP, SDP之类的规划问题显示起来效果还不错

KaTeX版本和XeLaTeX相比我觉得下标位置看起来还要更自然一点, 不过这里有巨大奇怪间隙. 行内公式还有些其他问题, 比如, 我怀疑我复制错了size1的sum或者KaTeX又做了不符合标准的修改…
4 接下来…
现在 Typst 看起来是个输出有点排版需求的html内容的好选择. 这里是个例子, 可以看到公式被Typst变成了svg. 效果不错, 但是不知道如果有很多公式的话绘制一堆svg会不会很慢, 页面会不会变得很大.
如果要修改的话, 我觉得会有很大的工作量. 一方面本身有点古老, 很多功能的实现方式太局限了. 另一方面我不懂js也不懂排版, 估计需要了解open type字体、unicode-math 的工作方式等.
4.1 Typst svg
用这个来让 Typst 在 html 导出中把所有公式都变成 svg.
#show math.equation: html.frame
#show math.equation.where(block: false): box
typst compile input.typ -f html htmloutput.html --features html
测试用的文档是 https://typst.app/project/rgLBUHLLRwTyTh16Ej3qlM
outputs | size |
---|---|
PDF-XeTeX | 25KB |
PDF-Typst | 39KB |
html-Typst | 194KB |
FiraMath font | 122KB |
5 MathJax 4.0 is out
https://docs.mathjax.org/en/latest/upgrading/whats-new-4.0.html
MathJax 支持 FiraMath. 所以不用再修改 KaTeX.