让 luatex 输出字形列表及其位置

让 luatex 输出字形列表及其位置

在 Python 绘图库 Matplotlib 中(https://matplotlib.org),可以使用 Matplotlib 自己的文本布局算法(其中包括一个用于解析 TeX 类数学模式语法子集的解析器)或使用 latex 来渲染文本:文本包装在 TeX 源文件中,由 (la)tex 处理,

  • 对于栅格后端,一方面我们解析 dvi 文件(使用自定义解析器 matplotlib.dviread)以提取字形的基线(以便多个文本对象可以相对于其基线对齐),另一方面我们使用 dvipng 将 dvi 转换为 png,然后加载 png 图像并将其渲染到 Matplotlib 的画布上;
  • 对于矢量后端(pdf/ps/svg),我们解析 dvi 文件以提取字形的基线以及字形和框的列表(例如,分数条在 dvi 文件中表示为矩形框),然后将字形和框渲染到矢量文件,再次考虑基线。

我想添加使用 luatex 而不是 tex 的支持;主要是为了改进字体支持。不幸的是,如其他地方所述[1],luatex 的 dvi 输出似乎无法以与 tex 相同的方式解析(由于对字体的引用不同),并且还会混淆 dvipng。除了尝试修复解析器之外,我想知道是否可以使用 luatex 的回调直接输出字形列表,即 {字体文件路径 + 面索引 + 字形索引 + 字形坐标} 列表和框列表?

(当文件(例如 .ttc 格式)包含多个面时,面索引是字体文件中面的索引,即https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Open_Face

[1]LuaTeX .dvi 文件中如何引用非 Unicode 字形?LuaLaTeX/dvipng:由于缺少字体,转换失败

提前致谢。

答案1

获取字体文件名和字形索引相当容易。我不知道您说的“面索引”是什么意思。获取页面上的位置要棘手得多,并且不包含在下面的示例中,因为在mlist_to_hlist触发回调时,尚不知道字形最终会出现在页面上的哪个位置。

\documentclass{article}
\usepackage{amsmath}
\usepackage{unicode-math}
\directlua{
local glyph_id = node.id("glyph")

recurse_sublists = function(head)
    for n in node.traverse(head) do
        if n.id == glyph_id then
            print("Glyph")
            print("  Filename: " .. font.fonts[n.font].filename)
            print("  Glyph index: " .. n.char)
        end
        if n.list then
            recurse_sublists(n.list)
        end
    end
end

local print_slots = function(head, display_type, penalties)
    local newhead = node.mlist_to_hlist(head, display_type, penalties)
    recurse_sublists(newhead)
    return newhead
end

luatexbase.add_to_callback("mlist_to_hlist", print_slots, "print_slots")
}
\begin{document}

\[
  \frac{1}{2\pi i} \int\limits_\gamma f\Bigl(x^{\mathbf{N}\in\mathbb{C}^{N\times 10}}\Bigr)
  = \sum_{k=1}^m n(\gamma;a_k)\operatorname{Res}(f;a_k)\,.
\]

\end{document}

在日志中我得到

Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 984713
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 984714
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 49
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 50
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 120587
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119894
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 984962
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 120574
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119891
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 984713
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119909
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm/lmroman7-bold.otf
 Glyph index: 78
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 8712
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 8450
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119873
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 215
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 49
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 48
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 984714
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 61
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119898
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 984973
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119896
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 61
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 49
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119899
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 40
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 120574
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 59
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119886
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119896
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 41
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm/lmroman10-regular.otf
 Glyph index: 82
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm/lmroman10-regular.otf
 Glyph index: 101
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm/lmroman10-regular.otf
 Glyph index: 115
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 40
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119891
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 59
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119886
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 119896
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 41
Glyph
 Filename: /usr/local/texlive/2018/texmf-dist/fonts/opentype/public/lm-math/latinmodern-math.otf
 Glyph index: 46

即使在您发表评论后,我仍然不确定您真正需要哪些信息。这就是为什么我实现了某种 JSON 序列化,它只是将完整的内容写入mlist文件。

\documentclass{article}
\usepackage{amsmath}
\usepackage{unicode-math}
\directlua{
local glyph_id = node.id("glyph")

f = io.open("\jobname.mlist", "w")

recurse_sublists = function(head, indent)
    indent = indent or 0
    local s = string.rep(" ", indent)
    f:write("{\string\n")
    for n in node.traverse(head) do
        for _,v in ipairs(node.fields(n.id)) do
        f:write(s .. '"' .. v .. '": ')
        if type(n[v]) == "number" then
            f:write(n[v])
        elseif type(n[v]) == "nil" then
            f:write('null')
        else
            f:write('"' .. tostring(n[v]) .. '"')
        end
        f:write(',\string\n')
        end
        if n.list then
            f:write(s .. '"list": ')
            recurse_sublists(n.list, indent + 2)
        end
    end
    f:write(string.rep(" ", indent - 2) .. "},\string\n")
end

local print_slots = function(head, display_type, penalties)
    local newhead = node.mlist_to_hlist(head, display_type, penalties)
    recurse_sublists(newhead, 2)
    return newhead
end

luatexbase.add_to_callback("mlist_to_hlist", print_slots, "print_slots")
}

\AtEndDocument{\directlua{f:close()}}
\begin{document}

\[
  \frac{1}{2\pi i} \int\limits_\gamma f\Bigl(x^{\mathbf{N}\in\mathbb{C}^{N\times 10}}\Bigr)
  = \sum_{k=1}^m n(\gamma;a_k)\operatorname{Res}(f;a_k)\,.
\]

\end{document}

相关内容