从 hlist 节点的描述来看luatex 手册,其字段“shift”似乎是垂直移位。但是当我使用 post_linebreak_filter 更改它时,它会将水平移位添加到 hlist。这背面邮报too 将 shift 描述为 hlist 的垂直移位:“元数据”中列出的另一个参数是 shift:这是应用 TeX 命令所产生的框位移值:\raise、\lower(应用于 \hbox);”我是否遇到了 luatex 中的错误,或者我的使用模式不正确?无论哪种方式,我都想选择一个 hlist 节点,并在页面上水平和垂直移动它,同时不影响页面上的其他 pdf 内容(实际上是将 pdf 平移矩阵应用于 hlist)。不幸的是,pdf_setmatrix
节点不能用于垂直/水平位移(在PDF 1.7 手册\pdfsetmatrix
)因为 pdftex 已禁用它(阅读中的定义pdftex 手册),并警告不要使用\pdfliteral
(pdftex 等同于 luatexpdf_literal
节点)。虽然我不确定在换行后阶段,luatex 的警告是否正确?如果正确,那么实现水平和垂直平移的最安全方法是什么?(我猜测水平平移是在 hlist 的开头添加一个 kern 节点,这是最干净的吗?我不确定进行垂直平移的最干净的方法是什么……)
下面是我得到的输出截图,后面是向第 3 行的 hlist 添加垂直和水平翻译的完整代码,代码下面是来自上面描述中提到的文档的一些有用的截图:
代码:>>lualatex test.tex
% test.tex
\documentclass[notitlepage,letterpaper]{article}
\usepackage[letterpaper,left=2in,right=2in,top=1in,bottom=1in]{geometry}
\usepackage{blindtext}
\directlua{
function my_post_lb_filter(head,groupcode)
local linenumber=1;
local HLIST = node.id("hlist")
local WHATSIT = node.id("whatsit")
local KERN = node.id("kern")
for n in node.traverse(head) do
if n.id==HLIST then
if linenumber==3 then
% Add vertical translation
n.shift=20*65536; % This should shift linenumber 3 vertically by 20, in reality it shifts horizontally
% Add horizontal translation
local hkern = node.new(KERN)
hkern.subtype=1;
hkern.attr=n.attr;
hkern.kern = 80*65535;
n.head = node.insert_before(n.list,n.head,hkern)
end
linenumber=linenumber+1;
end
end
return head
end
luatexbase.add_to_callback('post_linebreak_filter', my_post_lb_filter, 'Play with luatex node library')
}
\begin{document}
\blindtext[1]
\end{document}
luatex 手册中的 hlist shift 描述:
pdf对象翻译:
pdftex 手册中的 pdfliteral 与 pdfsetmatrix:
答案1
关于shift
:文档具有误导性,但如果框是垂直移动的包含在水平列表中(\lower
或\raise
在水平模式下),如果包含在垂直列表中(\moveleft
并且\moveright
处于垂直模式),并且如果它不在任何外部列表中,它根本不会移动。
因此,一个“修复”方法是将其包装在外部 hbox 中:
% test.tex
\documentclass[notitlepage,letterpaper]{article}
\usepackage[letterpaper,left=2in,right=2in,top=1in,bottom=1in]{geometry}
\usepackage{blindtext}
\directlua{
function my_post_lb_filter(head,groupcode)
local linenumber=1;
local HLIST = node.id("hlist")
local WHATSIT = node.id("whatsit")
local KERN = node.id("kern")
for n in node.traverse(head) do
if n.id==HLIST then
if linenumber==3 then
% Add vertical translation
n.shift=20*65536; % This should shift linenumber 3 vertically by 20, in reality it shifts horizontally
% Add horizontal translation
local hkern = node.new(KERN)
hkern.subtype=1;
hkern.attr=n.attr;
hkern.kern = 80*65535;
n.head = node.insert_before(n.list,n.head,hkern)
% We want to wrap n in a hlist, but we have to keep
% node.traverse happy so we can't easily change the
% current node. Instead, create a new hlist inside of the
% current list, inheriting all attributes and the content
% of n. Then this list becomes the new head of n.
%
% First a little optimization: We want to create a copy of n with
% local nn = node.copy(n)
% but doing so now would lead to n.head being deep-copied
% into nn.head. Given that we want to overwrite nn.head
% anyway, this would waste memory and time, especially if
% the line is very complicated. So save the line
local saved_head = n.head
% make it empty to hide it and avoid copying something
n.head = nil
% and then make the copy. Now nothing in n..head is copied
% (because nothing is there)
local nn = node.copy(n)
% Finally we again want nn to contain the original content contained by n, so assign the saved content.
nn.head = saved_head
% So much for the inner hlist nn. But what should be the new
% content of the outer hlist n? it should contain only the
% inner hlist nn. Given that nn was just created, it doesn't
% has a next node anyway, so we can just assign it as new head.
n.head = nn
n.shift = 0
end
linenumber=linenumber+1;
end
end
return head
end
luatexbase.add_to_callback('post_linebreak_filter', my_post_lb_filter, 'Play with luatex node library')
}
\begin{document}
\blindtext[1]
\end{document}
(此版本保留尺寸以模拟 PDF 运算符变体,从而导致重叠)
当然,在我看来,一个更好的选择就是使用正常的 kern 节点,就像水平定位一样:
\documentclass[notitlepage,letterpaper]{article}
\usepackage[letterpaper,left=2in,right=2in,top=1in,bottom=1in]{geometry}
\usepackage{blindtext}
\directlua{
function my_post_lb_filter(head,groupcode)
local linenumber=1;
local HLIST = node.id("hlist")
local WHATSIT = node.id("whatsit")
local KERN = node.id("kern")
for n in node.traverse(head) do
if n.id==HLIST then
if linenumber==3 then
% Add vertical translation
local vkern = node.new(KERN)
vkern.kern = 20*65536
head = node.insert_before(head, n, vkern)
if 'you want the text to overlap' then
vkern = node.copy(vkern)
vkern.kern = -vkern.kern
node.insert_after(head, n, vkern)
end
% Add horizontal translation
local hkern = node.new(KERN)
hkern.subtype=1;
hkern.attr=n.attr;
hkern.kern = 80*65535;
n.head = node.insert_before(n.list,n.head,hkern)
end
linenumber=linenumber+1;
end
end
return head
end
luatexbase.add_to_callback('post_linebreak_filter', my_post_lb_filter, 'Play with luatex node library')
}
\begin{document}
\blindtext[1]
\end{document}