@Martin is an TeX ninja. His answer, above, is the first fully-working solution to my original question. The use of zref-abspos
and zref-abspage
is smart, and it was quite informative to see how to convert from zref-abspos
positions to tikz
coordinates. I can offer some incremental improvements on his proof-of-concept, but he gets big kudos for showing how this can be done. Thanks, Martin!
My Modifications
My version, which appears below, makes the following improvements to Martin's original:
The magic yshift=.5ex
position adjustment is now computed automatically using \vcenter
. This should make stroke positioning more robust in the face of line height changes.
Page comparisons are always done between absolute page numbers, never between an absolute and a regular page number. This should improve robustness in complex documents with nontrivial page numbering schemes.
Conversion from zref
positions to tikz
coordinates now takes advantage of the standard shift=
diagram option instead of calculating offsets explicitly. This improves readability and avoids loading up the tikz
calc
library.
I use atbegshi
instead of everypage
for my per-page hook. The zref-abspage
package already needs atbegshi
anyway, so this avoids bringing in an additional package. A second benefit to atbegshi
is that \baselineskip
can now be used to set the tikz
line width, which does not work well with everypage
.
I loop over the numbered highlights using \forloop
from the forloop
package instead of a recursive macro call. (There is still a recursive macro call deep inside \forloop
, but that is hidden away as an implementation detail.) Likewise, I'm using \ifthenelse
from the ifthen
package instead of lower-level TeX conditionals. I generally prefer to program up at the LaTeX layer as much as possible for better error checking and better long-term readability.
I've factored out some common code for extracting the absolute page and the tikz
coordinates of a zref
reference, again for better long-term readability.
I've added the warning for cross-page highlights that Martin suggested in his solution.
I've generally replaced the term "stroke" with "highlight" to better reflect the intended use of this code, and included @
symbols in all counter and macro names that are internal to the implementation, not intended for use by the document author.
Sample Document
I'll offer my revised solution and the example document separately, to make it easier for folks to extract just the former for their own future use. Here's the example document, which is the same as that Martin used:
\documentclass[12pt]{article}
\usepackage{highlighter}
\usepackage[paperheight=7cm]{geometry}
\renewcommand{\thepage}{\roman{page}}
\begin{document}
This text is \HighlightFrom before the figure both in the \LaTeX{}
source and in the\HighlightTo{} rendered document.
This text is \HighlightFrom before the figure both in the \LaTeX{}
source and in the\HighlightTo{} rendered document.
This text is \HighlightFrom before the figure both in the \LaTeX{}
source and in the\HighlightTo{} rendered document.
\begin{figure}[p]
\centering
\HighlightFrom Once upon a time.\HighlightTo
\end{figure}
This text is after the figure in the \LaTeX{} source but before
\HighlightFrom it in the rendered document.\HighlightTo
This text is after the figure in the \LaTeX{} source but before
\HighlightFrom it in the rendered document.\HighlightTo
\clearpage
\begin{figure}
\centering
\HighlightFrom in a far far away place\HighlightTo
\end{figure}
This text is after the figure on a new page in the \LaTeX{} source but
before \HighlightFrom it in the rendered document.\HighlightTo
\end{document}
Highlighter Implementation
And here is the implementation of the solution, which should be saved as highlighter.sty
before rendering the example document:
\RequirePackage{atbegshi}
\RequirePackage{forloop}
\RequirePackage{ifthen}
\RequirePackage{tikz}
\RequirePackage{zref-abspage}
\RequirePackage{zref-abspos}
% customizable by package user
\tikzset{highlighter/.style = {yellow, line width = \baselineskip}}
% anchor placement, with @highlight counting upward to generate unique names
\newcounter{@highlight}
\newcommand{\@HighlightAnchor}[1]{\ensuremath{\vcenter{\zsavepos{highlight-#1}}}}
\newcommand{\HighlightFrom}[0]{\stepcounter{@highlight}\@HighlightAnchor{begin-\the@highlight}}
\newcommand{\HighlightTo}[0]{\@HighlightAnchor{end-\the@highlight}}
% highlight painting, with @@highlight counting upward to consider all defined highlights
\newcounter{@@highlight}
\newcommand{\@HighlightPage}[1]{\zref@extract{highlight-#1-\the@@highlight}{abspage}}
\newcommand{\@HighlightCoords}[2]{(#1\zposx{highlight-#2-\the@@highlight}sp, #1\zposy{highlight-#2-\the@@highlight}sp)}
\AtBeginShipout{
\AtBeginShipoutUpperLeft{
% consider every highlight until reaching one that is undefined
\forloop{@@highlight}{1}{\@HighlightPage{begin} > 0}{
% page highlight if it begins and ends on the current page
\ifthenelse{\@HighlightPage{begin} = \value{abspage}}{
\ifthenelse{\@HighlightPage{end} = \value{abspage}}{
% drop an anchor here so we compute the proper (x, y) offsets
\zsavepos{highlight-draw-\the@@highlight}%
\tikz[overlay, shift={\@HighlightCoords{-}{draw}}]{
\draw [highlighter] \@HighlightCoords{}{begin} -- \@HighlightCoords{}{end};
}}
{\PackageWarning{highlighter}{highlight \protect#\the@@highlight\space crosses from page \@HighlightPage{begin} to page \@HighlightPage{end}}}}
{}}}}
Again, big thanks to Martin for showing us how this could be done. I'm just putting the final polish on his gemstone.
Let's start of with an minimal example - something that really helps the community, regardless of what you may think, really. The following is taken from the KOMA-script documentation (section 4.20. Closing, p 190):
\documentclass[foldmarks=true,foldmarks=blmtP,
fromphone,fromemail,fromlogo,
subject=titled,
version=last]{scrlttr2}% http://ctan.org/pkg/koma-script
\usepackage[english]{babel}% http://ctan.org/pkg/babel
\usepackage{graphicx}% http://ctan.org/pkg/graphicx
\begin{document}
\setkomavar{fromname}{John Public}
\setkomavar{signature}{John Public\\
(former chairman)}
\renewcommand*{\raggedsignature}{\raggedright}
\setkomavar{fromaddress}{Valley 2\\
54321 Public-Village}
\setkomavar{fromphone}{0\,12\,34~56\,78}
\setkomavar{fromemail}{Peter@Public.invalid}
\setkomavar{fromlogo}{\includegraphics[height=5\baselineskip]{tiger}}
\setkomavar{location}{\raggedright
Club nember no.~4711\\
since 11.09.2001\\
chairman 2003--2005}
\setkomavar{date}{29th February 2011}
\setkomavar{place}{Public-Village}
\setkomavar{subject}{Missing general meeting}
\begin{letter}{%
Joana Public\\
Hillside 1\\
12345 Public-City%
}
\opening{Dear chairman,}
the last general meeting was about one year ago.
I want to remind you, that the constitution of our
club advises you to make a general meeting every
six month. Because of this I expect the executive
board to detain such a meeting immediately.
\closing{Expecting an invitation}
\ps PS: I hope you accept this as an friendly
demand note.
\setkomavar*{enclseparator}{Enclosure}
\encl{Compendium of the constitution with the
general meeting paragraphs.}
\cc{executive board\\all members}
\end{letter}
\end{document}
This is what the output looks like:
If we wish to modify the structure of the \closing
, we should modify what is contained within the \parbox
command. Let's do this using etoolbox
in the form of a \patchcmd
:
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\makeatletter
\patchcmd{\closing}% <cmd>
{\parbox}% <search>
{\parbox{\linewidth}{\raggedsignature\strut\ignorespaces\let\\\relax%
#1 \usekomavar{signature}}%
\@gobbletwo}%< <replace>
{}{}% <success><failure>
\makeatother
The above code replaces \parbox
for \parbox{..}{...}\@gobbletwo
. The replacement \parbox{..}{...}
uses elements of the older \parbox
, but doesn't insert a sigbeforevskip
length that used to produce the vertical gap. Instead, \usekomavar{signature}
is set with a space between the actual \closing{#1}
. Also, \\
is \let
to \relax
(but might not be necessary) to avoid forced paragraph breaks. The latter \@gobbletwo
eats the old \parbox
's two arguments.
Here's an example document showing the output results (note that I've also moved a \ps
below \encl
and \cc
, as requested):
\documentclass[foldmarks=true,foldmarks=blmtP,
fromphone,fromemail,fromlogo,
subject=titled,
version=last]{scrlttr2}% http://ctan.org/pkg/koma-script
\usepackage[english]{babel}% http://ctan.org/pkg/babel
\usepackage{graphicx}% http://ctan.org/pkg/graphicx
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\makeatletter
\patchcmd{\closing}% <cmd>
{\parbox}% <search>
{\parbox{\linewidth}{\raggedsignature\strut\ignorespaces\let\\\relax%
#1 \usekomavar{signature}}%
\@gobbletwo}%< <replace>
{}{}% <success><failure>
\makeatother
\begin{document}
\setkomavar{fromname}{John Public}
\setkomavar{signature}{John Public\\
(former chairman)}
\renewcommand*{\raggedsignature}{\raggedright}
\setkomavar{fromaddress}{Valley 2\\
54321 Public-Village}
\setkomavar{fromphone}{0\,12\,34~56\,78}
\setkomavar{fromemail}{Peter@Public.invalid}
\setkomavar{fromlogo}{\includegraphics[height=5\baselineskip]{tiger}}
\setkomavar{location}{\raggedright
Club nember no.~4711\\
since 11.09.2001\\
chairman 2003--2005}
\setkomavar{date}{29th February 2011}
\setkomavar{place}{Public-Village}
\setkomavar{subject}{Missing general meeting}
\begin{letter}{%
Joana Public\\
Hillside 1\\
12345 Public-City%
}
\opening{Dear chairman,}
the last general meeting was about one year ago.
I want to remind you, that the constitution of our
club advises you to make a general meeting every
six month. Because of this I expect the executive
board to detain such a meeting immediately.
\closing{Expecting an invitation}
\setkomavar*{enclseparator}{Enclosure}
\encl{Compendium of the constitution with the
general meeting paragraphs.}
\cc{executive board\\all members}
\ps PS: I hope you accept this as an friendly
demand note.
\end{letter}
\end{document}
Of course, other adjustments can also be made.
Best Answer
In a comment has been required to have the page number centered below the footrule and a URL also centered, but above the footrule. Here's one possibility:
With the help of the
etoolbox
package, one can patch the\@fancyfoot
command and the code simplifies: