[Tex/LaTex] Installing background and foreground page layers with TikZ

backgroundsoutput-routineoverlaystikz-pgf

Several times I discovered the need to draw TikZ material behind and on top of the page text (How to draw text-anchored tikz line below text instead of above?, Test if a paragraph has a page break in it? and also Cool Text Highlighting in LaTeX). Most the time I need to draw from a start marker in the text towards a stop marker. As long as there are no page breaks between them I can draw in the text foreground when I draw from the end marker backwards (because the text is already typeset before) or in the background from the start marker forwards (because the text is typeset afterwards). However, as seen in How to draw text-anchored tikz line below text instead of above? this isn't perfect when drawing downwards to the right which goes over existing text to the left. Also in the case of one (or even multiple!) page break(s) between these markers the drawing must be split into multiple operations. Then it is difficult to ensure all material is placed in the correct layer.

My idea is now the following: I like to install a background and a foreground layer of the whole page and allow macros to place drawing commands on these layers. I think all commands can be accumulated and then processed when the page is shipped out. For this I found the atbegshi package which provides access to the page as box. I now manipulate this box be placing it in a TikZ picture which is stored back in the same box register. See the example code below.

My question now is:

Is this an appropriate way to do it, i.e. is it safe to manipulate the page box like this or is there a better way to do this?

I now about \AtBeginShipoutUpperLeft etc. but had problems using it with TikZ. Therefore I'm using the box in a node.

\documentclass{article}

\usepackage{atbegshi}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\usepackage{lipsum}

% Proof-of-concept
% Later these would be numbered to allow multiple per page
\def\mybgstart{%
    \tikz[overlay,remember picture] { \draw [yellow] circle (1pt); \coordinate (bgstart); }%
    \gdef\drawinbackground{\draw [yellow,line width=5mm] (bgstart) -- (bgend);}%
}
\def\mybgend{\tikz[overlay,remember picture] { \draw [blue] circle (1pt); \coordinate (bgend); }}

\def\myfgstart{%
    \tikz[overlay,remember picture] { \draw [yellow] circle (1pt); \coordinate (fgstart); }%
    \gdef\drawinforeground{\draw [purple,line width=5mm] (fgstart) -- (fgend);}%
}
\def\myfgend{\tikz[overlay,remember picture] { \draw [blue] circle (1pt); \coordinate (fgend); }}

\begin{document}
\lipsum[1-3] % for comparison
\clearpage

\makeatletter
\AtBeginShipout{%
\setbox\AtBeginShipoutBox\hbox{%
    \color@setgroup
    \begin{tikzpicture}[line width=1cm,remember picture]%
        \path [use as bounding box] node [inner sep=0pt,outer sep=0pt] (A) {\box\AtBeginShipoutBox};
        \begin{pgfonlayer}{background}
        \draw [green,line width=1cm] (A.north east) -- (A.south west);
        \drawinbackground
        \global\let\drawinbackground\empty
        \end{pgfonlayer}
        \draw [red] (A.north west) -- (A.south east);
        \drawinforeground
        \global\let\drawinforeground\empty
    \end{tikzpicture}%
    \color@endgroup
}}
\makeatother

\lipsum[1]
\mybgstart\lipsum*[2]\unskip\mybgend

\lipsum[3]

\myfgstart\lipsum*[4]\unskip\myfgend

\lipsum[5-10]


\end{document}

Result

PS: The above code works well with pdflatex but I get an offset with latex (DVI mode). With it the .aux file holds different \pgfsyspdfmark values. I there a way to fix that?

Best Answer

My approach for a similar effect. Declare the backgrounds globally for TikZ:

\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}

Then a command to place "markers" within normal text:

% place an inline node that is remembered for tikz
% \tikzremember{<node name>}
%   note: you have to compile twice
\newcommand{\tikzremember}[1]{{
  \tikz[remember picture,overlay]{\node (#1) at (0,11pt) { };}
}}

and in the document use it:

\tikzremember{bgstart}\lipsum*[2]\unskip\tikzremember{bgend}

Now, i have TikZ nodes with the page and can just draw with them like i want and any layer i want. For example, one your big green line:

\begin{tikzpicture}[remember picture,overlay]
\begin{pgfonlayer}{background}
\draw [green,line width=1cm] (bgstart.north east) -- (bgend.south west);
\end{pgfonlayer}{background}
\begin{pgfonlayer}{foreground}
\draw [green,line width=1cm] (bgstart.north east) -- (bgend.south west);
\end{pgfonlayer}{foreground}
\end{tikzpicture}

This technique is stolen from http://www.texample.net/tikz/examples/oxidation-and-reduction/