暂时先记在这里,我想到的是:我使用的方法是在为什么 \vspace 在节标题之后有时会以离散步骤跳跃/捕捉?基本上就是让一个bash
脚本调用pdflatex
X 次,每次都使用一个参数的新值\mylength
,并生成 X 个输出 PDF 文件。显然,每次pdflatex
调用时,它都必须重新加载\documentclass
,然后\usepackage
重新加载,等等——总之,很耗时。
我在想 - 如果在 .tex 文档的某个点上我可以写类似这样的内容(伪代码),那就更好了:
...
blah blah.
\newlength{\mylength}
\steplength{\mylength}{2.5pt}{20pt}{0.5pt} % pseudo
\generateParameterSequencePages{} % pseudo
\begin{minipage}{\textwidth}
\textbf{Something here}
\vspace{\mylength}
\textit{Something else here}
\end{minipage}
Blah blah blah....
...因此当 tex 引擎遇到 时\generateParameterSequencePages
,它基本上会“保存”当前页面的状态;创建一个新文件,,\jobname_pgY.pdf
用当前页码( \jobname 文档中的 Y )编号;并且在这个新文件内,它会抛出 Z 次迭代(这\steplength{\mylength}{startvalue}{endvalue}{step}
将指定)\mylength
当前页面中的页面,作为单独的页面。完成后,引擎退出 (不确定此时我是否希望引擎返回到 tex 原始 PDF)。
因此,我最终会得到一个新文件\jobname_pgY.pdf
,其中包含 Z 页,显示参数的 Z 次迭代\mylength
及其对原始\jobname.pdf
文档中第 Y 页布局的影响。我可以想象这会比每次都bash
调用脚本更快一些。pdflatex
使用当前的引擎是否可能synctex
实现这样的事情?使用 会有什么不同吗?使用 怎么样luatex
?
非常感谢您的任何建议,
干杯!
编辑:另请参阅这个帖子以获得更详细的lualatex
例子。
答案1
为什么不直接使用一个 PDF 文件来生成,\foreach
这几乎是我在tikz 中的埃拉托斯特尼筛法制作动画:
\documentclass{article}
\usepackage{pgffor}
\begin{document}
\foreach \len in {2.5, 3.0, ..., 20.0}{%
\newpage%
\begin{minipage}{\textwidth}%
\textbf{Something here}
\vspace{\len pt}
\textit{Something else here}
\end{minipage}%
}%
\end{document}
答案2
我将在这里发布此内容,以免阻塞原始问题。
但基本上,这个问题背后的意图是调试长度对页面排版的影响......我现在已经对其进行了一些研究,并且可以提供部分答案:synctex
“只是”为GUI编辑器建立了源.tex和输出.pdf之间的对应关系 - 但是,lualatex
这已经有助于更好地理解事情了。
所以,我一直在研究lua-visual-debug.lua/.sty;LuaTEX 参考手册 (luatexref-t.pdf);\AtBeginShipout
来自包阿特别格什和输出例程和 \box255基本上,我想处理这样的情况:
\documentclass[12pt]{article}
\usepackage{lipsum}
\begin{document}
\newlength{\mylength}
\section{Lorem Ipsum}
\lipsum[1-6]
\setlength{\mylength}{5pt}
\vspace*{\mylength}
\section{Sed commodo}
\lipsum[7-12]
\end{document}
在上面的例子中,我想看看不同的\mylength
s 对页面排版的影响。问题是我们不知道第二部分最终会出现在哪一页(好吧,我已经排版过一次文件,所以我知道它会出现在第 2 页 - 但是,我们事先并不知道这一点)。但无论如何,latex 必须至少排版一次,直到该\mylength
部分。
现在,据我(粗略)理解,\mylength
超过此部分后,tex 引擎将继续添加页面元素,直到页面溢出。此时,我们可以利用\AtBeginShipout
运行宏或 lua 脚本 - 显然有些事情能可以在那里进行更改;但我还不确定要更改哪些内容或如何更改它们。
在下面的例子中,我使用了 lua 代码(其原始设置来自lua-visual-debug.lua)基本上遍历了所谓的中的所有节点AtBeginShipoutBox
。运行时\AtBeginShipout
,AtBeginShipoutBox
本质上是\box256
;\box255
而是nil
。
这告诉我输出例程可能尚未运行 - 而且很可能尚未生成 pdf 页面(并且终端日志确实显示了脚本输出,在 pdf 页面生成时输出的字符串之前[1]
,[2]
我猜)。
因此显然,应该有可能改变一些事情 - 但是,我尝试在例程tex.print("\\mylength=20pt ")
中插入一个“黑客” \AtBeginShipout
- 不幸的是,生成的 PDF 中完全没有任何变化。
然而,如果那里有发生了变化;那么我可以想象以下解决方案:
- 在 tex 文件中我们要检查的位置放置一个“标记”(例如
\setlength
本文第一个例子中的命令) - 运行乳胶
- 跑步
\AtBeginShipout
- 此页面上是否出现过标记?如果出现:
- 保存页面上下文(开头的样式)
- 设置
\mylength
为迭代的第一步 - 暂时切换输出到另一个 pdf
- 运行输出例程并输出单页
- 从现在开始,不是将执行优先级返回给 latex!
- 开始循环直到迭代的最后一步
- 检索页面上下文
- 更改
\mylength
至下一步 - 运行输出例程并输出单页
- (重复循环)
因此,这里有两个问题:
- 我们可以改变类似
\mylength
在 ; 中运行的 lua 代码之类的东西吗,以便 latex 使用新的;\AtBeginShipout
重新排版页面;\mylength
- 是否有可能检索类似“页面上下文”(“样式”:页面排版开始时的字体、跳过等)的内容,保存它,然后再次检索已保存的版本,就像在 lua 代码中运行一样
\AtBeginShipout
?
至于“页面上下文”,我会考虑\baselineskip
在页面排版开始时的值,比如说和这样的值(这是由 luatex 提供的tex.baselineskip
);但如果环境(如列表)有效(我不知道 luatex 是否允许检查这一点);大概,对于 luatex 提供的那些变量,以某种方式保存它们的值应该不是问题。但是tex.baselineskip
在给定页面排版开始\AtBeginShipout
时\baselineskip
;或者在页面末尾(如果你\setlength{\baselineskip}{...}
在页面中间有一个)?
好吧,这就是我现在能得到的——以我对这个过程的有限理解,看起来做这样的事情是可能的,尽管我找不到确切的程序。所以如果知道这种方法是否从根本上是不可能的(至少对于当前版本的软件来说),那就太好了。此外,可能相关的是:在 LuaTeX 中并发交叉执行 Lua 和 TeX。
无论如何,这里是上面的例子,添加了 lua 函数来迭代并打印出页面的节点列表到终端:
\documentclass[12pt]{article}
\usepackage{lipsum}
%\usepackage{everyshi} % use atbegshi instead
\usepackage{atbegshi}
\usepackage{ifluatex}
\ifluatex
\usepackage{luacode}
\begin{luacode*}
--~ module(...,package.seeall)
--~ module("...","package.seeall")
-- running this \AtBeginShipout will typeset "test" (with the quotes) on start of every page other than first (regularly broken paragraph continues)
function mytest()
tex.sprint([["test"]]) -- typesets "test" (w/ quotations)
end
-- texlive/2011/texmf-dist/tex/context/base/node-ini.lua
local function simplified(t)
local r = { }
for k, v in next, t do
r[k] = string.gsub(v,"_","")
end
return r
end
local function table2string(t)
local ret = ""
for i,v in ipairs(t) do
-- print(i,v)
ret = ret .. "[" .. i .. "]= " .. tostring(v) .. "; "
end
return ret
end
function print_basic_nodedata()
local rep = "\n"
rep = rep .. " ## node.types: " .. table2string(node.types()) .. "\n" -- doesn't list whatsit?!
rep = rep .. " ## node.whatsits: " .. table2string(node.whatsits()) .. "\n"
rep = rep .. " ## tex: " .. tostring(tex) .. " / " .. table2string(tex) .. "\n" -- empty at this point
return rep
end
print(print_basic_nodedata()) -- once here, as well
-- texlive/2011/texmf-dist/tex/context/base/node-ini.lua
function nodes_fields(n)
local id = n.id
--local node_fields = node.fields
--local nodecodes = node.types() -- simplified(node.types())
--local whatsit_node = nodecodes.whatsit -- whatsit not listed in node.types(); go explicitly
--print(id .. " / " .. table2string(nodecodes) .. " / " .. tostring(whatsit_node))
local whatsit_node = 8
if id == whatsit_node then
return node.fields(id,n.subtype) --node_fields
else
local t = node.fields(id)
return t
end
end
function node_field_vals(n)
local id = n.id
local myfields = nodes_fields(n)
local rep = ""
local whatsit_node = 8
local whatsit_node_subtypes = node.whatsits()
for k, v in next, myfields do
if ((k>0) and not(v=="head")) then -- k=0 next; k=-1 prev; k=12 head; avoid those
local vv = ""
if (v == "subtype") then
if (n.id == whatsit_node) then
vv = " (" .. tostring(whatsit_node_subtypes[n.subtype]) .. ")"
end
end
rep = rep .. ".[" .. k .. "/" .. v .. "]= " .. tostring(n[v]) .. vv .. "; "
end
end
if (n.id == whatsit_node) then
if (n.subtype == 1) then -- 1: "write"
rep = rep .. table2string(n.data[1])
end
end
return rep .. "\n"
end
level = 0
-- texlive/2011/texmf-dist/tex/luatex/lua-visual-debug/lua-visual-debug.lua
function show_page_elements(parent)
local head = parent.list
level = level + 1
print("") -- just a newline
while head do
local spacer = ""
for i=1,level,1 do
spacer = spacer .. " "
end
print(level .. spacer .. ": " .. tostring(head) .. "/" .. head.id)
--texio.write("term and log", "\nsomething\n" )
-- below print is for more verbose information:
--~ print (" " .. spacer .. ": " .. node_field_vals(head) )
if head.id == 0 or head.id == 1 then -- hbox / vbox
show_page_elements(head)
end
head = head.next
end
level = level - 1
return true
end
function start_inspect_page()
print("")
print("Start inspect page")
print("tex.output: " .. tex.output) -- shows "{\let \par \@@par \ifnum \outputpenalty <-\@M \@specialoutput ..."
print("tex.box[255]: " .. tostring(tex.box[255])) -- nil here
print("tex.box[256]: " .. tostring(tex.box[256]))
print("tex.box[AtBeginShipoutBox]: " .. tostring(tex.box["AtBeginShipoutBox"])) -- same as 256; as it says in log file: "\AtBeginShipoutBox=\box256"
--~ print(print_basic_nodedata()) -- same as the first time
show_page_elements(tex.box["AtBeginShipoutBox"])
-- perform hack
tex.print("\\mylength=20pt ")
-- tex.tprint({-2,\\mylength=20pt}) -- gets typeset
end
\end{luacode*}
\AtBeginShipout {%
%\directlua{mytest()}
\directlua{start_inspect_page()}
}
\else
\fi
\begin{document}
\newlength{\mylength}
\section{Lorem Ipsum}
% \directlua{mytest()}
\showboxdepth=100
\showboxbreadth=100
% \showbox255 % > \box255=void here
% \showbox256 % > \box256=void here
\lipsum[1-6]
\setlength{\mylength}{5pt}
\vspace*{\mylength}
\section{Sed commodo}
\lipsum[7-12]
\end{document}
编辑:刚刚对进行了一些实验tex.set
;似乎有些东西可以在中改变\AtBeginShipout
,并且仍然对生成的 PDF 产生影响,例如voffset
:
-- tex.voffset = "-2cm" -- works!
-- tex.set ('global', 'voffset', '2cm') --works!
-- tex.set ('global', '\\voffset', '2cm') -- nowork
tex.set ('voffset', '-2cm') --works!
但是,tex.parindent
在手册的同一页“4.13.1.2 尺寸参数”中列出,但是tex.voffset
,在 PDF 上看到变化效果的唯一方法是global
:
--tex.set ('parindent', '2cm') -- nowork
tex.set ('global', 'parindent', '2cm') -- work
这样做的好处是,它显示了单词的换行方式不同,我想这“证明”我们可以在这里更改内容 - 并且 latex 会排版包含更改。这是个好消息。请注意tex.baselineskip
不同之处:
-- tex.set ('baselineskip', '2cm') -- "There should have been a lua <node> here, not an object with type string!:"
-- tex.set ('\baselineskip', '20cm') -- pass, nowork
-- tex.set ('\\baselineskip', '20cm') -- pass, nowork
...并且手册还指出:“4.13.1.4 ... glue 参数接受并返回代表 glue_spec 节点的用户数据对象“
但是,我仍然找不到改变的方法\mylength
,tex.set
所以这仍然是问题的一部分......