Installing background and foreground page layers with TikZ

11,166

Solution 1

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/

Solution 2

I don't have anything to say about the "shoulds" and "shouldn'ts" of this, being none too aware of the potential issues involved, but I thought I'd share something I came across the other day that might be of use.

In trying to work out how beamer builds a frame (insert link here), I took a close look at the beamer code. It turns out that the background layers are inserted by hooking in to the headers and footers. Since TeX puts the headers and footers in first they can be used to put stuff behind the page. I don't know if this is any better than what you're doing, and it only addresses the background part, but here's a proof-of-concept that does highlighting.

The actual highlighting is not all that sophisticated (as this is a proof-of-concept). What it does is imagine that you have a highlighter pen and draw it across the page, starting at a certain point and ending at another point. So, in particular, it doesn't try to follow the lines of text, but it does ensure that it gets everything in between the starting and ending points.

Of course, one would need to be careful with the actual headers to ensure that they were typeset correctly. Also, it doesn't worth with the standalone class, as far as I can tell.

Result:

highlighting behind the page

Code:

\documentclass{article}
\pagestyle{empty}
\usepackage{tikz}
\makeatletter
\newbox\bg@tempbox
\newdimen\bg@tempdim
\def\ps@background{%
  \def\@oddhead{%
  \begingroup
  \setbox\bg@tempbox=\hbox{\begin{tikzpicture}[remember picture,overlay]
      \coordinate (page west);
      \coordinate (path north);
      \path  (\textwidth,0) coordinate (page east);
      \path (0,\textheight) coordinate (page south);
      \bg@contents
    \end{tikzpicture}}%
    \wd\bg@tempbox=0pt\ht\bg@tempbox=0pt\dp\bg@tempbox=0pt%
    \vbox{\hbox{\box\bg@tempbox}}%
    \global\let\bg@contents=\@empty
    \endgroup\hfil}
  \let\@evenhead\@oddhead
}
\pagestyle{background}
\def\bg@contents{%
}
\newcommand{\tikzmark}[1]{\tikz[remember picture,overlay] \coordinate (#1);}

\newcommand{\addtobg}[1]{%
  \g@addto@macro\bg@contents{#1}%
}

\newcounter{highlight}
\newcommand{\hlstart}{\tikz[remember picture,overlay,baseline=-0.7ex] \coordinate (hlstart\the\value{highlight});\hl@start}
\newcommand{\hlend}{\tikz[remember picture,overlay,baseline=-0.7ex] \coordinate (hlend\the\value{highlight});\hl@end\stepcounter{highlight}}

\newcommand{\hl@start}{%
  \edef\@temp{%
    \noexpand\addtobg{\noexpand\hl@draw{\the\value{highlight}}}%
  }%
  \@temp
}

\newcommand{\hl@end}{}

\newcommand{\hl@draw}[1]{%
  \path (hlstart#1);
  \pgfgetlastxy{\hlsx}{\hlsy}%
  \path (hlend#1);
  \pgfgetlastxy{\hlex}{\hley}%
  \ifdim\hlsy=\hley\relax
  \draw[highlight] (hlstart#1) -- (hlend#1);
  \else
  \draw[highlight] (hlstart#1) -- (hlstart#1 -| page east);
  \pgfmathtruncatemacro{\bg@lines}{int((\hley - \hlsy)/12pt) + 1}%
  \foreach \bg@line in {-1,...,\bg@lines} {
    \path (hlstart#1) ++(0,\bg@line * 12pt) coordinate (bgtmp);
    \draw[highlight] (bgtmp -| page west) -- (bgtmp -| page east);
  }%
  \path (hlstart#1) ++(0,\bg@lines * 12pt - 12pt) coordinate (bgtmp);
  \draw[highlight] (bgtmp -| page west) -- (hlend#1);
  \fi
}

\tikzset{%
  highlight/.style={
    yellow,
    line width=12pt,
  }
}

\makeatother


\begin{document}

One of the suggested uses for this blog is to \hlstart highlight great questions\hlend\ and answers.
I'm proposing the following question for a \textbf{Great Question}.
(I'm linking to it early in case you get bored with the blog post and just want to look at the question.)

Good keyboard layouts for typing (La)TeX.

To encourage you to look at that, let me first divulge my reason why I consider that a Great Question (and no, it's not because I answered it).
\hlstart I don't intend to be prescriptive about what a Great Question is, but certainly one good indicator is that it is a question that you should read even if you don't know that you should read it\hlend.
What I mean by that is that this question is probably one that you would pass in the street if you came upon it, but that once you've actually read it you will (I hope) think, ``I wish I'd read that years ago!''.

The rest of this post is for those of you who want a little more reason for reading it, or who having read it don't quite get what I'm making all the fuss about.
\end{document}
Share:
11,166

Related videos on Youtube

Martin Scharrer
Author by

Martin Scharrer

Updated on September 05, 2020

Comments

  • Martin Scharrer
    Martin Scharrer about 3 years

    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?

  • Martin Scharrer
    Martin Scharrer over 12 years
    Yes, that's the normal way to do it. The posts I linked in my answers also use code like this. The issue here is that the background and foreground layers are local to the picture and because the normal text is not part of that the background layer isn't placed behind the text.
  • Martin Scharrer
    Martin Scharrer about 12 years
    AFAIK, the header is placed first, then the main content box and then the footer. So the foreground layer could be placed in the footer. I know about this and like to avoid it so I don't have to worry about the real header and footer etc.
  • Andrew Stacey
    Andrew Stacey about 12 years
    @Martin: Okay, didn't know that (you didn't mention it in your question). Moreover, I strongly suspect that you know far more about all of this than I do! I just wanted to draw your (and others) attention to this. Since beamer does use this method, I've now adapted it for beamer and use it successfully in my lectures.