![多行、多页 \phantom 模拟宏](https://linux22.com/image/418424/%E5%A4%9A%E8%A1%8C%E3%80%81%E5%A4%9A%E9%A1%B5%20%5Cphantom%20%E6%A8%A1%E6%8B%9F%E5%AE%8F.png)
我需要一个宏来pdflatex(编辑:或路拉泰克斯如果需要的话),删除一些文本/公式/图像可以写很多段落和页面,无需改变布局 (其位置必须有一个大小完全相同的空白空间)。
这会像\phantom
但是作为一个环境并接受许多段落、分页符等一样工作...我认为它已经存在,但我找不到任何解决方案(拥有更通用的 \phantomplus 和 phantomplusenv 宏可能是一个好主意 - phantomplus 包的想法?;-))。
目前,我只是使用\color{white}
隐藏文本|公式,但这还不够(文本仍在 pdf 中,可选择等...)。
我看见如何用相同大小的空块替换大块文本?但对于我的情况没有可用的解决方案。
如果这是一个好的、现实的想法,该怎么做?或者其他想法(使用 lualatex?)?
答案1
在 LuaLaTeX 中,这可以类似于 lua-ul 和 luacolor 实现:使用属性标记所有应删除的文本,然后挂接到 shipout 例程中以删除/替换为空白:
使用以下代码创建一个 Lua 文件hideme.lua
(内嵌说明)
local set_func = luatexbase.new_luafunction'hideme.set_attribute'
local reset_func = luatexbase.new_luafunction'hideme.reset_attribute'
local process_func = luatexbase.new_luafunction'hideme.process_attribute'
local functions = lua.get_functions_table()
-- Define the attribute we use as marker
local attr = luatexbase.new_attribute'hide_marker'
-- This function will later activate the hiding. It could be implemented in TeX, but then we would have to make the attribute number available there
functions[set_func] = function()
tex.attribute[attr] = 1
end
functions[reset_func] = function()
tex.attribute[attr] = -0x7FFFFFFF
end
-- Just some shorter names to improve readability and performance
local glue_id = node.id'glue'
local vlist_id = node.id'vlist'
local hlist_id = node.id'hlist'
local whatsit_id = node.id'whatsit'
local rule_id = node.id'rule'
local direct = node.direct
local setglue = direct.setglue
local getid = direct.getid
local todirect = direct.todirect
local getlist = direct.getlist
local setlist = direct.setlist
local getleader = direct.getleader
local traverse = direct.traverse
local free = direct.free
local flush_list = direct.flush_list
local has_attribute = direct.has_attribute
local rangedimensions = direct.rangedimensions
local getprev = direct.getprev
local slide = direct.slide
local node_new = direct.new
local setlink = direct.setlink
local flatten_discretionaries = direct.flatten_discretionaries
-- We later want to remove nodes while we are traversing over them, so add a helper which ensures that deletion gets delayed until we no longer need to look at the node
local delayed_free do
local delayed
function delayed_free(n)
if delayed then free(delayed) end
delayed = n
end
end
local do_vhide
-- Iterate over a horizontal list and hide marked nodes:
local function do_hhide(parent, list)
local work_done, begin_hide
list = flatten_discretionaries(list) -- Nobody likes disc nodes anyway
slide(list) -- Ensure that we can use getprev
for n, id, sub in traverse(list) do
local hide_this
-- We have to recursivly visit vlist and hlist nodes
if id == vlist_id then
do_vhide(n)
elseif id == hlist_id then
setlist(n, (do_hhide(n, getlist(n))))
-- Everything else gets deleted if it is marked
elseif has_attribute(n, attr) then
hide_this = true
if not begin_hide then
-- Actually we don't really delete yet, we only mark for deletion
begin_hide = n
end
-- Again, recursively iterate leaders
elseif id == glue_id and sub >= 100 then -- leaders
local leader = getleader(n)
local leader_id = leader and getid(leader)
if leader_id == hlist_id then
setlist(leader, do_hhide(leader, getlist(leader)))
elseif leader_id == vlist_id then
do_vhide(leader)
end -- else rule --> ignore
end
if not hide_this and begin_hide then
-- Now we have to actually remove the nodes from begin_hide to this point. Let's first measure what we got:
local nglue = node_new(glue_id)
setglue(nglue, rangedimensions(parent, begin_hide, n))
-- Remove n from the list starting at begin_hide
setlink(getprev(n), nil)
-- And integrate nglue in the list without the deleted nodes
if list == begin_hide then
list = setlink(nglue, n)
else
setlink(getprev(begin_hide), nglue, n)
end
-- Now we can delete the list of hidden nodes
flush_list(begin_hide)
begin_hide = nil
work_done = true
end
end
if begin_hide then
-- We end with some hidden nodes. No need for glue here, just delete them
if list == begin_hide then
list = nil
else
setlink(getprev(begin_hide), nil)
end
flush_list(begin_hide)
work_done = true
end
return list, work_done
end
-- In vboxes, the situation is a bit different. It is harder to measure nodes here because rangedimensions doesn't work, but very few node types actually have to be hidden
function do_vhide(parent)
local list = getlist(parent)
for n, id, sub in traverse(list) do
-- Again recurse into the usual suspects (No discretionaries here)
if id == vlist_id then
do_vhide(n)
elseif id == hlist_id then
setlist(n, (do_hhide(n, getlist(n))))
elseif has_attribute(n, attr) then
-- Here we actually remove directly
if id == glue_id and sub >= 100 then -- leaders
-- Just convert them into "regular" glue
flush_list(getleader(n))
direct.setleader(n, nil)
direct.setsubtype(n, 0)
elseif id == rule_id and sub ~= 3 then
-- rules (also includes images etc.) Convert into invisible rules
direct.setsubtype(n, 3) -- empty rule
elseif id == whatsit_id then
-- whatsit - We don't know what they do exactly, so better delete it completly
list = direct.remove(list, n)
delayed_free(n)
end
elseif id == glue_id and sub >= 100 then -- leaders
local leader = getleader(n)
local leader_id = leader and getid(leader)
if leader_id == hlist_id then
setlist(leader, do_hhide(leader, getlist(leader)))
elseif leader_id == vlist_id then
do_vhide(leader)
end -- else rule --> ignore
end
end
setlist(parent, list)
end
-- Now just dome driver to call the function above for a given box
functions[process_func] = function()
local box = todirect(tex.box[token.scan_int()])
local box_id = box and getid(box)
if box_id == hlist_id then
setlist(box, do_hhide(box, getlist(box)))
else
do_vhide(box)
end
delayed_free()
end
-- And give TeX accessible names to our functions
token.set_lua('HideMeStart', set_func, 'global', 'protected')
token.set_lua('HideMeReset', reset_func, 'global', 'protected')
token.set_lua('HideMeProcessBox', process_func, 'global', 'protected')
您可以从 TeX 中使用它(基于 Ulrike 的示例)
\documentclass{article}
\usepackage{transparent}
\usepackage{lipsum}
\usepackage{graphicx}
\usepackage{atbegshi}
\directlua{require'hideme'}
\makeatletter
% Don't hide content inserted in the output routine
\output\expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter\HideMeReset\expandafter\@firstofone\the\output}
\makeatother
\AtBeginShipout{\HideMeProcessBox\AtBeginShipoutBox}
\begin{document}
abc
\begingroup
some text \[a=b=2\] more text
\rule{1cm}{1cm}
\includegraphics[width=5cm]{example-image-duck}
\endgroup
blub
abc
\begingroup\HideMeStart
some text \[a=b=2\] more text
\rule{1cm}{1cm}
\includegraphics[width=5cm]{example-image-duck}
\endgroup
blub
\end{document}
答案2
多行,单页解决方法是使用包\pgfsys@begininvisible
提供\pgfsys@endinvisible
的pgf
后端tikz
。
这两个命令之间的内容实际上是排版的,但偏移量很大(x = 20000bp,y = 20000bp)。beamer
课堂上的覆盖实用程序也使用这对命令。
\documentclass{article}
\usepackage{lipsum}
\usepackage{pgf}
\begin{document}
\makeatletter
\lipsum[1]
\pgfsys@begininvisible
\lipsum[2] % the output of this line is moved out of the page
\pgfsys@endinvisible
\lipsum[3]
\makeatother
\end{document}
答案3
你可以使用透明包。但是它只会使内容透明,它仍然存在,例如复制和粘贴:
\documentclass{article}
\usepackage{transparent}
\usepackage{lipsum}
\usepackage{graphicx}
\begin{document}
abc
\begingroup
some text \[a=b=2\] more text
\rule{1cm}{1cm}
\includegraphics[width=5cm]{example-image-duck}
\endgroup
blub
abc
\begingroup\transparent{0}
some text \[a=b=2\] more text
\rule{1cm}{1cm}
\includegraphics[width=5cm]{example-image-duck}
\endgroup
blub
\end{document}