我需要在 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
outlinetext
ConTeXt 中的代码似乎无法在 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 的回答展示如何将上述字形绘制函数转换为所需的字符串绘制函数。