多行、多页 \phantom 模拟宏

多行、多页 \phantom 模拟宏

我需要一个宏来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@endinvisiblepgf后端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}

在此处输入图片描述

相关内容