#tex #latex #unicode-characters #rustex

tex-glyphs

一个用于处理TeX/pdfTeX字体中字符的crate

2个版本

0.1.1 2024年2月2日
0.1.0 2024年1月28日

#973 in 编码

GPL-3.0-or-later

125KB
1.5K SLoC

一个用于处理TeX字体中码点的crate。


lib.rs:

这个crate提供了一种访问TeX字体中字符的方法。它旨在由使用tex_engine的crate使用。

TeX通过解析字体度量文件.tfm文件)来处理字体,这些文件包含字体中每个字符尺寸的信息。因此,从TeX(核心)的角度来看,一个字符只是一个指向字体度量文件的索引 $0 \leq i \leq 255$。

为了找出字符实际的外观,我们理想情况下想了解相应的Unicode码点。这个crate试图做到这一点。

用法

这个crate试图将一个tex字体(通过其.tfm文件的文件名基础标识)与

  1. 一系列FontModifier(例如粗体、斜体、无衬线等)相关联
  2. 一个GlyphList,即一个长度为256的数组 [Glyph;256]

一个Glyph要么是未定义的(即该字符不在字体中,或者crate无法确定其确切内容)或者可以呈现为一个字符串。

例如,考虑\mathbf{\mathit{\Gamma^\kappa_\ell}}(即 $\mathbf{\mathit{\Gamma^\kappa_\ell}}$)。从TeX的角度来看,这是一个由3个字符组成的序列,表示为字体 cmmib10 的索引,即0、20和96。

下面是如何使用这个crate来获取相应的Unicode字符,即𝜞𝜿的示例。

实例化

首先,我们使用一个函数来实例化一个 FontInfoStore,该函数允许它找到文件。这个函数应该接受一个字符串(例如 cmmib10.tfm)并返回一个字符串(例如 /usr/share/texmf-dist/fonts/tfm/public/cm/cmmib10.tfm)。例如,可以通过调用 kpsewhich 来完成,但重复和频繁地调用 kpsewhich 很慢,所以建议使用更高效的替代方案。

use tex_glyphs::encodings::FontInfoStore;
let mut store = FontInfoStore::new(|s| {
std::str::from_utf8(std::process::Command::new("kpsewhich")
.args(vec!(s)).output().expect("kpsewhich not found!")
.stdout.as_slice()).unwrap().trim().to_string()
});

这个存储现在将使用提供的函数来查找您的 pdftex.map 文件,该文件列出了 TeX 可用的所有字体,并将它们与 .enc.pfa.pfb 文件相关联。

获取字形

如果我们现在查询存储以获取某些字体(例如 cmmib10)的 GlyphList,如下所示

let ls = store.get_glyphlist("cmmib10");

...它将尝试解析与 cmmib10 相关的 .enc 文件,如果存在的话。如果没有,或者解析失败,它将尝试解析 .pfa.pfb 文件。如果这两个都不起作用,它将搜索 .vf 文件并尝试解析它。如果这也失败了,它将返回一个空的 GlyphList

从这三个来源中的任何一个,它都会尝试将每个字节索引与一个 Glyph 相关联

let zero = ls.get(0);
let twenty = ls.get(20);
let ninety_six = ls.get(96);
println!("0={}={}, 20={}={}, and 96={}={}",
zero.name(),zero,
twenty.name(),twenty,
ninety_six.name(),ninety_six
);
0=Gamma=Γ, 20=kappa=κ, and 96=lscript=ℓ

字体修饰符

到目前为止,一切顺利 - 但字形不是粗体或斜体,而是在 cmmib10 中它们是。所以让我们来看看 cmmib10 有什么属性

let font_info = store.get_info("cmmib10").unwrap();
println!("{:?}",font_info.styles);
println!("{:?}",font_info.weblink);
ModifierSeq { blackboard: false, fraktur: false, script: false, bold: true, capitals: false, monospaced: false, italic: true, oblique: false, sans_serif: false }
Some(("Latin Modern Math", "https://fonts.cdnfonts.com/css/latin-modern-math"))

...这告诉我们该字体是粗体和斜体的,但不是无衬线,等宽等。它还告诉我们,该字体的公开可用的网络兼容等价字体称为 "Latin Modern Math",并且如果我们想在例如 HTML 中使用它,我们可以通过提供的 URL 找到它 :)

现在我们只需要将修饰符应用到字形上

use tex_glyphs::fontstyles::FontModifiable;
println!("{}, {}, and {}",
zero.to_string().apply(font_info.styles),
twenty.to_string().apply(font_info.styles),
ninety_six.to_string().apply(font_info.styles)
);
𝜞, 𝜿, and ℓ

apply 方法来自 trait FontModifiable,该 trait 为任何实现了 AsRef<str> 的类型实现,包括 &strString。它还提供了更直接的方法,例如 make_boldmake_italicmake_sans 等。

修正错误

上述确定字形和字体修饰符的程序绝对不是完美的;不仅因为 encpfa/pfb 文件可能包含错误或不为人知的字形名称,而且还因为字体修饰符是通过启发式方法确定的。因此,我们提供了一种修正错误的方法

  1. 字形名称到 Unicode 的映射存储在文件 glyphmap.txt
  2. 字体修饰符、网络字体名称和链接,甚至完整的字形列表都可以添加到 markdown 文件 patches.md 中,该文件还作为修复任何可能发现的错误的指南。

这两个文件在编译过程中都会被解析。

如果您注意到任何错误,请随时为这些文件打开一个 pull request。

依赖项

~1.3–2MB
~36K SLoC