edward-martyr / kanbun

Easily typeset kanbun-kundoku (漢文訓読) with (Lua)LaTeX
15 stars 1 forks source link

Automatically adjust the vertical kerning of 「一レ」by loading glyph shapes from fonts #1

Open tanukihee opened 2 years ago

tanukihee commented 2 years ago

感觉也没有什么好方法?也没有类似于 xe 那样的获取 glyph 边界的命令,顶多加个选项控制 trim 的比例?

image image

edward-martyr commented 2 years ago

嗯,我也在想这个问题,方法应该还是有的:https://tex.stackexchange.com/a/451951/179770,不过目前还没有仔细研究过这个代码。主要是不懂 METAFONT/MetaPost,得从头研究一下怎么工作的。

edward-martyr commented 2 years ago

代码方面基本研究明白了,先写个草稿,

\documentclass[tate]{jlreq}

\usepackage{luacode}
\begin{luacode*}
-- adapted from https://tex.stackexchange.com/a/451951

-- We need some utilities from ConTeXt
callbacks = callbacks or {}
callbacks.supported = callbacks.supported or {}
dofile(kpse.find_file("util-fmt.lua"))
dofile(kpse.find_file("node-ini.lua"))
dofile(kpse.find_file("font-mps.lua"))
-- dofile(kpse.find_file("font-shp.lua")) -- unnecessary on current TeX version

-- That's a simple REImplemetation of ConTeXt's \showshape macro
function outlinejfontpaths(character)
    local fontid = font.current()
    -- prioritise using tate luatexja font
    local curjfnt = tex.getattribute('ltj@curjfnt')
    local curtfnt = tex.getattribute('ltj@curtfnt')
    if curjfnt >= 0 then
        fontid = curjfnt
    end
    if curtfnt >= 0 then
        fontid = curtfnt
    end

    local shapedata   = fonts.hashes.shapes[fontid] -- by index
    local chardata    = fonts.hashes.characters[fontid] -- by unicode
    local shapeglyphs = shapedata.glyphs or { }

    character = utf.byte(character)
    local c = chardata[character]
    if c then
        if not c.index then
            return {}
        end
        local glyph = shapeglyphs[c.index]
        if glyph and (glyph.segments or glyph.sequence) then
            local units  = shapedata.units or 1000
            local factor = 100/units
            local paths  = fonts.metapost.paths(glyph,factor)
            return paths
        end
    end
end
\end{luacode*}

\usepackage{luamplib}
\mplibsetformat{metafun}
\everymplib{beginfig(0);}
\everyendmplib{endfig;}

\edef\letterhash{\string#}
\def\mpdefineoutlines#1#2{\directlua{
    local char = "\luaescapestring{#2}"
    local outlines = outlinejfontpaths("#1")
    local len = \letterhash outlines
    tex.print("path " .. char .. "[];")
    tex.print(char .. "n := " .. len .. ";")
    for i, path in ipairs(outlines) do
        tex.print(char .. "[" .. i .. "] := " .. path .. ";")
    end
}}

\newbox\mympbox

\setbox\mympbox\hbox{
\begin{mplibcode}
pair shift; shift := (0pt,-27pt);

\mpdefineoutlines{一}{ICHI}
\mpdefineoutlines{レ}{REI}

path r;
numeric n; n := 0;

r := ICHI[1];
forever:
    pair q;
    r := r cutbefore (reverse REI[1] shifted (shift) );
    exitif length cuttings = 0;
    r := subpath(epsilon, length r) of r;
    q = point 0 of r;
    n := n + 1;

    drawdot(q);
endfor;

\end{mplibcode}
}

\newcommand\countmp{\directlua{tex.sprint(node.length(tex.box.mympbox.head))}}

\begin{document}

\countmp

\end{document}

这样通过修改 shift 来测试移到什么地方可以使「一レ」刚刚接触,\countmp 输出 3 是不接触,4 是有接触,shift 的单位是 pt/100pt。metafont 好像没办法直接输出变量给 TeX,所以只能通过 box 这样 hack 一下。

排版方面,最简单的实现就是把刚刚好接触的「一レ」排出来,不过不知道是不是稍微重叠一些会更好……

edward-martyr commented 2 years ago

https://github.com/edward-martyr/kanbun/pull/4

@tanukihee 请看一下这样符不符合要求,用 \usepackage[ichire]{kanbun} 开启自动调整「一レ」间距。

tanukihee commented 2 years ago

在某些字体下似乎会报错?

MWE

\documentclass{ltjtarticle}
\usepackage[match]{luatexja-fontspec}
\setmainjfont{Yu Gothic}
\usepackage[ichire]{kanbun}

\Kanbun
孤之有ルハ[二]孔明[一],猶ホ‹ごと›«キ»[二]魚之有ルガ[一レ]水也。
\EndKanbun

\begin{document}
    \printkanbun
\end{document}

编译命令

lualatex

输出(截取第一个错误)

(c:/texlive/2021/texmf-dist/tex/luatex/luamplib/luamplib.sty)[\directlua]:1: at
tempt to get length of a nil value (local 'outlines')
stack traceback:
        [\directlua]:1: in main chunk
        [C]: in function 'tex.runtoks'
        c:/texlive/2021/texmf-dist/tex/luatex/luamplib/luamplib.lua:376: in upvalue 'r
un_tex_code'
        c:/texlive/2021/texmf-dist/tex/luatex/luamplib/luamplib.lua:678: in field 'pro
cess_mplibcode'
        [\directlua]:1: in main chunk.
\mpdefineoutlines ..."] := " .. path .. ";") end }

l.112 }

完整 log

kanbun-example.log

edward-martyr commented 2 years ago

嗯,而且我测试下来好像就是系统自带的字体会出问题……