TeX - LaTeX Asked by alfazaz on October 2, 2021
I need a macro to be able, in pdflatex (EDIT : or lualatex if necessary), to remove some text/formulas/images which can go on many paragraphs and pages, without changing the layout (there must be an empty space with the exact same size at its place).
This would work like phantom
but, as an environment and accepting many paragraphs, page breaks etc… I thought it already exists but I can’t find any solution (it could be a good idea to have more general phantomplus and phantomplusenv macros – idea for a phantomplus package ? 😉 ).
For now, I simply use a color{white}
to hide text|formulas but it’s not sufficient (text is still in the pdf, is selectable etc…).
I saw How to replace a large block of text by an empty block of the same size? but there is no available solution in it for my situation.
If it is a good and realistic idea, how to do this ? Or other idea (with lualatex ?) ?
In LuaLaTeX, this can be implemented similar to lua-ul and luacolor: Use an attribute to mark all text that should be removed, then hook into the shipout routine to delete/replace with empty space:
Create a Lua file hideme.lua
with (explanations inline)
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')
You can use this from TeX as (based on Ulrike's example)
documentclass{article}
usepackage{transparent}
usepackage{lipsum}
usepackage{graphicx}
usepackage{atbegshi}
directlua{require'hideme'}
makeatletter
% Don't hide content inserted in the output routine
outputexpandafterexpandafterexpandafter{expandafterexpandafterexpandafterHideMeResetexpandafter@firstofonetheoutput}
makeatother
AtBeginShipout{HideMeProcessBoxAtBeginShipoutBox}
begin{document}
abc
begingroup
some text [a=b=2] more text
rule{1cm}{1cm}
includegraphics[width=5cm]{example-image-duck}
endgroup
blub
abc
begingroupHideMeStart
some text [a=b=2] more text
rule{1cm}{1cm}
includegraphics[width=5cm]{example-image-duck}
endgroup
blub
end{document}
Correct answer by Marcel Krüger on October 2, 2021
A multi-line, single-page workaround is to use pgfsys@begininvisible
and pgfsys@endinvisible
provided by pgf
package, the backend of tikz
.
Contents in between these two commands are actually typeset but with a large amount of shift (x = 20000bp, y = 20000bp). The overlay utility in beamer
class uses this pair of commands as well.
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}
Answered by muzimuzhi Z on October 2, 2021
You could use the transparent package. But it will make the content only transparent, it is still there, e.g. for copy&paste:
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
begingrouptransparent{0}
some text [a=b=2] more text
rule{1cm}{1cm}
includegraphics[width=5cm]{example-image-duck}
endgroup
blub
end{document}
Answered by Ulrike Fischer on October 2, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP