有没有办法在 LuaLaTeX 中的 MetaPost 中获取字形/文本轮廓?

有没有办法在 LuaLaTeX 中的 MetaPost 中获取字形/文本轮廓?

我需要在 LuaLaTeX 中获取 MetaPost 中某些文本的轮廓路径,以便使用它们进行进一步的操作,类似于您在 ConTeXt 中可以执行的操作:

\starttext
    \startMPcode
        picture p;
        p := outlinetext("TEST") scaled 10;
        for i within p:
            j := j + 1;
            drawarrow pathpart i;
        endfor;
    \stopMPcode
\stoptext

在此处输入图片描述

outlinetextConTeXt 中的代码似乎无法在 LuaLaTeX 下运行,例如我也没法工作。有什么办法可以实现吗?

答案1

解决这个问题的第一个方法是简单地打开metafun提供的格式luamplib,如下所示:

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibsetformat{metafun} 
\begin{mplibcode}
beginfig(1);
     picture p;
        p := outlinetext("BEST") scaled 10;
        for i within p:
            j := j + 1;
            drawarrow pathpart i;
        endfor;

endfig;
\end{mplibcode}
\end{document}

metafun格式提供了一个outlinetext宏,但不幸的是,在我的 TexLive 2023 副本中它不起作用。如果我用编译上述文档lualatex,我会收到以下错误消息(并且没有输出):

mplib warning: error in script: [string "mp.mf _outline_text(1,[===[BEST]===],[===[]===..."]:1: attempt to call a nil value (field 'mf_outline_text')
mplib warning: error in script: [string "mp.mf_get_outline_text(1)"]:1: attempt to call a nil value (field 'mf_get_outline_text')

因此,第二种方法是定义我自己的outlinetext宏。 Context 实现相当复杂,并且正确处理字距调整和垂直移动等,但制作一个忽略所有这些复杂性并适用于简单情况的版本并不难。

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
vardef outlinetext(expr s) = 
  save c, g, x; string c; picture g; numeric x;
  image(
    for i = 1 upto length s:
      c := substring (i-1, i) of s;
      g := glyph ASCII c of defaultfont scaled 1/64;
      x := xpart lrcorner currentpicture;
      for item within g:
        draw pathpart item shifted (x, 0);
      endfor
    endfor
  )
enddef;
beginfig(1);
  % defaultfont := "pplri8r";  % <- uncomment to try another font
  ahangle := 30;
  picture p; p = outlinetext("BESTA&?") scaled 10;
  for item within p:
    drawarrow pathpart item;
  endfor;
endfig;
\end{mplibcode}
\end{document}

编译此文件lualatex可获得如下 PDF:

在此处输入图片描述

答案2

欺骗 LaTeX 加载 ConTeXt 支持代码相当容易,因此我们可以制作一个非常接近 ConTeXtoutlinetext函数的复制品:

\documentclass{article}
\pagestyle{empty}

\usepackage{luamplib}

{\catcode`\%=12
\directlua{
    do --[[ Define some variables that ConTeXt expects to be defined ]]
        nodes.rulecodes = {}
        nodes.nuts = node.direct
        nodes.nuts.isglyph = node.direct.is_glyph
        nodes.nuts.effectiveglue = node.direct.effective_glue
        function nodes.nuts.getreplace(n)
            local _, _, h, _, _, t = node.direct.getdisc(n,true)
            return h, t
        end

        --[[ Load the ConTeXt Lua module ]]
        require("font-mps")
    end

    --[[ Expose the Lua function to Metapost ]]
    luamplib.everymplib[""] = luamplib.everymplib[""] .. [[
        def textoutline (text t) =
            runscript("textoutline('" & t & "')")
        enddef;
    ]]

    function textoutline(text)
        --[[ Create a box holding the provided text ]]
        local box = tonumber(
            luamplib.maketext(text):match("mplibtexboxid=(%d+)")
        )

        --[[ Convert the box to a MetaPost string ]]
        local mp_str = fonts.metapost.boxtomp(box)

        --[[ Clean up the MetaPost code so that it works with LaTeX ]]
        mp_str = mp_str:gsub("mfun_do_outline_text_flush%([^,]-,[^,]-,([%d.-]+),([%d.-]+),[^)]-%)(%b());", "draw %3 shifted (%1,%2);")
                       :gsub("checkbounds%b();", "")

        mp_str = "image(" .. mp_str .. ")"

        --[[ Insert the MetaPost code into the document ]]
        mp.print(mp_str)
    end
}}

\usepackage{fontspec}
\setmainfont{texgyrechorus-mediumitalic}

\begin{document}
    \begin{mplibcode}
        beginfig(1);
            picture t; t := textoutline("\\TeX \\textsf{\\TeX}") scaled 10;
            for item within t:
                fill pathpart item withcolor .9white;
                draw pathpart item dashed evenly withcolor red;
            endfor
        endfig;
    \end{mplibcode}
\end{document}

输出

MetaPost 手册中给出的示例无需修改即可使用,但条件是你只能使用老式的 Type 1 字体:

\documentclass{article}
\pagestyle{empty}

\usepackage{luamplib}

\begin{document}
    \begin{mplibcode}
        beginfig(1);
            picture q; path p;
            interim ahlength := 12bp;
            interim ahangle := 25;

            q := glyph "Dcaron" of "ec-lmr10" scaled .2;

            for item within q:
                p := pathpart item;

                drawarrow p withcolor (.6,.9,.6)
                    withpen pencircle scaled 1.5;

                for j=0 upto length p:
                    pickup pencircle scaled .7;
                    draw (point j of p -- precontrol j of p)
                        dashed evenly withcolor blue;

                    draw (point j of p -- postcontrol j of p)
                        dashed evenly withcolor blue;

                    pickup pencircle scaled 3;
                    draw precontrol j of p withcolor red;
                    draw postcontrol j of p withcolor red;

                    pickup pencircle scaled 2;
                    draw point j of p withcolor black;
                endfor
            endfor
        endfig;
    \end{mplibcode}
\end{document}

输出

Thruston 的回答展示如何将上述字形绘制函数转换为所需的字符串绘制函数。

相关内容