7

I would like to add a sort of a watermark to a PDF file produced using LaTeX. I have in mind graphical elements (lines, circles, etc.) that would partially obscure the text on the page. The arrangement (and perhaps the shape and the number of) the elements should be different on every page, and it would be best if it could be derived from a pseudorandom seed given in the document, so different compilations would produce the same arrangement of elements.

As a bonus, I'd like to protect parts of the text from being obscured by those random lines and squiggles - instead of obscuring those parts, the watermarks could pass "under" a white rectangle with them on top, or just not appear where such protected text is. It's not a problem to mark such parts inside the LaTeX document.

My use case is a visible watermark for document tracking, with a very rudimentary anti-OCR feature (since some letters in the text would be obscured). Let me preemptively say that I am well aware of the ability to copy text from PDF, the possibility of retyping the document, etc.

Now the question is where to start looking for a solution - TikZ is able to draw geometric shapes pretty well, but I have no idea how to make them random and different on every page, nor how to protect parts of text... any pointers would be appreciated.

4
  • 1
    You can open the PDF in any vector graphics editor, delete the shapes and get a clean version of the document. Nov 17, 2011 at 9:12
  • Do you plan to hand out the pdf file or a paper copy only? If you give away the pdf file, your anti-OCR-feature does not make sense at all. For your watermark question, maybe you could use a QR code for this, see i.e. this QR code question on s.tk/tex
    – matth
    Nov 17, 2011 at 10:43
  • I know that objects in the PDF can be manipulated, and that giving out a PDF file with such "protection" would not be a good idea at all. A QR code would not be a good fit - a machine-readable tagging system for documents is not what I had in mind, but rather something more human-readable (or human-recognizable, I suppose), and more tied to the text. However, I was not aware that LaTeX had the pst-barcode package, and it looks interesting, so thanks very much for pointing it out to me!
    – Neith
    Nov 17, 2011 at 21:26
  • Keep in mind: The better OCR development, the less human-readable is any anti-OCR text (I myself sometimes fail todays captchas!). For any text of nontrivial length, human reading becomes intolerably strenuous (not to mention the visually impaired) Nov 15, 2014 at 14:55

2 Answers 2

5

Here's a quick and dirty solution:

\documentclass{article}

\makeatletter
\usepackage{tikz}
\usepackage{everypage}

\pgfmathsetseed{314}

\newlength{\obfobjectsize}
\setlength{\obfobjectsize}{36pt}
\newcommand{\obftext}{obfuscated}

\newcommand{\dontobfuscate}[1]{%
  \ifmmode\let\@dollar=$\else\let\@dollar=\relax\fi
  \vphantom{#1}\smash{\fboxsep=0pt\colorbox{white}{\@dollar #1\@dollar}}%
}

\newcommand{\setrandomcoordinates}{% Places random coordinates (in pt)
  \pgfmathrnd                      % in \a and \b.
  \let\a=\pgfmathresult
  \pgfmathmultiply{\a}{\paperwidth}%
  \let\a=\pgfmathresult
  % 
  \pgfmathrnd
  \let\b=\pgfmathresult
  \pgfmathmultiply{\b}{\paperheight}%
  \let\b=\pgfmathresult
}
\newcommand{\tkzplacerandomline}{
  \setrandomcoordinates
  %
  \pgfmathrand
  \let\c=\pgfmathresult
  \pgfmathmultiply{\c}{\obfobjectsize}%
  \let\c=\pgfmathresult
  % 
  \pgfmathrand
  \let\d=\pgfmathresult
  \pgfmathmultiply{\d}{\obfobjectsize}%
  \let\d=\pgfmathresult
  % 
  \coordinate[xshift=\a,yshift=\b] (a) at (current page.south west);
  \coordinate[xshift=\c,yshift=\d] (b) at (a);
  \draw[ultra thick] (a) -- (b);
}
\newcommand{\tkzplacerandomcircle}{
  \setrandomcoordinates
  %
  \pgfmathrnd
  \let\c=\pgfmathresult
  \pgfmathmultiply{\c}{\obfobjectsize}%
  \let\c=\pgfmathresult
  % 
  \coordinate[xshift=\a,yshift=\b] (a) at (current page.south west);
  \draw[ultra thick] (a) circle (\c pt);
}
\newcommand{\tkzplacerandomnode}{%
  \setrandomcoordinates
  %
  \pgfmathrandominteger{\c}{30}{330}
  %
  \coordinate[xshift=\a,yshift=\b] (a) at (current page.south west);
  \node[rotate=\c] at (a) {\obftext};
}

\newcommand{\placerandomobjects}[2]{%
  \begin{tikzpicture}[overlay,remember picture]
    \foreach \n in {1,2,...,#2} { #1 }
  \end{tikzpicture}%
}

\AddEverypageHook{
\placerandomobjects{\tkzplacerandomline}{100}
\placerandomobjects{\tkzplacerandomcircle}{100}
\placerandomobjects{\tkzplacerandomnode}{100}
}

\makeatother

\begin{document}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus
elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur
dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id,
vulputate a, magna.  Donec vehicula augue eu neque. Pellentesque
habitant morbi tristique senectus et netus et malesuada fames ac
turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla
et lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit
amet tortor gravida placerat. Integer sapien est, iaculis in, pretium
quis, viverra ac, nunc. \dontobfuscate{Praesent eget sem vel leo ultrices
bibendum}. Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar
at, mollis ac, nulla. Cur- abitur auctor semper nulla. Donec varius
orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis
quis, diam. Duis eget orci sit amet orci dignissim rutrum.

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel,
wisi. Morbi auctor lorem non justo. Nam lacus libero, pretium at,
lobortis vitae, ultricies et, tellus. Donec aliquet, tortor sed
accumsan bibendum, erat ligula aliquet magna, vitae ornare odio metus
a mi. Morbi ac orci et nisl hendrerit mollis. Suspendisse ut
massa. Cras nec ante. Pellentesque a nulla. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus
mus. Aliquam tincidunt urna.

Nulla ullamcorper vestibulum turpis. Pellentesque cursus luctus
mauris.  Nulla malesuada porttitor diam. Donec felis erat, congue non,
volutpat at, tincidunt tristique, libero. Vivamus viverra fermentum
felis. \dontobfuscate{$E=m(a^2+b^2)$} Donec nonummy pellentesque
ante. Phasellus adipiscing semper elit. Proin fermentum massa ac
quam. Sed diam turpis, molestie vitae, placerat a, molestie nec,
leo. Mae- cenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec,
suscipit a, ipsum.  Morbi blandit ligula feugiat magna. Nunc eleifend
consequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt
purus vel magna. Integer non enim.  Praesent euismod nunc eu
purus. Donec bibendum quam in tellus. Nullam cur- sus pulvinar
lectus. Donec et mi. Nam vulputate metus eu enim. Vestibulum
pellentesque felis eu massa.

Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vitae
lacus tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. In hac habitasse platea dictumst. Integer tempus
convallis augue. Etiam facilisis.
\begin{displaymath}
  \dontobfuscate{E=m(a^2+b^2)}
\end{displaymath}
Nunc elementum fermentum
wisi. Aenean placerat. Ut imperdiet, enim sed gravida sollicitudin,
felis odio placerat quam, ac pulvinar elit purus eget enim.  Nunc
vitae tortor. Proin tempus nibh sit amet nisl. Vivamus quis tortor
vitae risus porta vehicula.
\end{document}

It is not very elegant, and especially the \dontobfuscate command is really very simple; it will work in horizontal mode (and generate a box, so it will be not breakable and the spaces will have their natural width, which will look ugly unless (a) only individual words are put in it or (b) the text is set ragged right or something similar; it will also work in math mode, but in a very primitive fashion (suitable for e.g. simple symbols). But it works as a proof of concept, and making it more versatile is now a question of some tweaking. Have fun!

PS. Not to mention that the "drm" tag might be considered a bit, say, offensive by some people in this community;).

Edit: as cjorssen mentioned in the comment, this needs two-pass compilation, since it uses the remember picture mechanism of tikz.

3
  • Maybe you could add that one need two compilations to get the correct output.
    – cjorssen
    Nov 17, 2011 at 10:19
  • Very good point. I'll do it now.
    – mbork
    Nov 17, 2011 at 10:34
  • Thanks, this does exactly what I had in mind! Oh, and about the drm tag - I thought it would actually fit the best even though it's not really about that.
    – Neith
    Nov 17, 2011 at 21:16
4

This is a possibility using TikZ everyshi and the invert clipping trick used in @Jake's answer over here: How can I invert a 'clip' selection within TikZ?

This is the resulting code:

\documentclass{article}
\usepackage{everyshi}
\usepackage{tikz}
\usetikzlibrary{calc}
\def\nodrmstart{\tikz[remember picture, overlay]\coordinate(nodrms);}
\def\nodrmend{\tikz[remember picture, overlay]\coordinate(nodrme);}
\EveryShipout{%
  \begin{tikzpicture}[overlay, remember picture]
    \tikzstyle{reverseclip}=[insert path={(0,0) --
      ++(\textwidth,0) --
      ++(0,-\textheight) --
      ++(-\textwidth,0) --
      (0,0)}
    ]
    \begin{pgfinterruptboundingbox}
      \path[clip] let \p1=(nodrms), \p2=(nodrme) in (\textwidth,\y1) -- (0,\y1) -- (0,\y2) -- (\textwidth,\y2) -- cycle [reverseclip];
    \end{pgfinterruptboundingbox}
    \pgfmathsetseed{2}
    \foreach \i in {1,2,...,200}{
      \pgfmathsetlengthmacro{\yloc}{random(0,int(\the\textheight))}
      \pgfmathsetlengthmacro{\xloc}{random(0,int(\the\textwidth))}
      \pgfmathsetlengthmacro{\rad}{random(5,30)}
      \draw (\xloc, -\yloc) circle[radius=\rad];
    }%
  \end{tikzpicture}
}
\begin{document}
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida
mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna.
Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra
metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus
eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium
quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean
faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Cur-
abitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue
eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim
rutrum.
    Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi
auctor lorem non justo. Nam lacus libero, pretium at, lobortis vitae, ultricies et,
tellus. Donec aliquet, tortor sed accumsan bibendum, erat ligula aliquet magna,
vitae ornare odio metus a mi. Morbi ac orci et nisl hendrerit mollis. Suspendisse
ut massa. Cras nec ante. Pellentesque a nulla. Cum sociis natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. Aliquam tincidunt urna.
Nulla ullamcorper vestibulum turpis. Pellentesque cursus luctus mauris.
    Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at,
tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec nonummy
pellentesque ante. Phasellus adipiscing semper elit. Proin fermentum massa
ac quam. Sed diam turpis, molestie vitae, placerat a, molestie nec, leo. Mae-
cenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec, suscipit a, ipsum.
Morbi blandit ligula feugiat magna. Nunc eleifend consequat lorem. Sed lacinia
nulla vitae enim. Pellentesque tincidunt purus vel magna. Integer non enim.
Praesent euismod nunc eu purus. Donec bibendum quam in tellus. Nullam cur-
sus pulvinar lectus. Donec et mi. Nam vulputate metus eu enim. Vestibulum
pellentesque felis eu massa.
    Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vitae lacus
tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In
hac habitasse platea dictumst. Integer tempus convallis augue. Etiam facilisis.
Nunc elementum fermentum wisi. Aenean placerat. Ut imperdiet, enim sed
gravida sollicitudin, felis odio placerat quam, ac pulvinar elit purus eget enim.
Nunc vitae tortor. Proin tempus nibh sit amet nisl. Vivamus quis tortor vitae
risus porta vehicula.
    Fusce mauris. Vestibulum luctus nibh at lectus. Sed bibendum, nulla a fau-
cibus semper, leo velit ultricies tellus, ac venenatis arcu wisi vel nisl. Vestibulum
diam. Aliquam pellentesque, augue quis sagittis posuere, turpis lacus congue
quam, in hendrerit risus eros eget felis. Maecenas eget erat in sapien mattis
porttitor. Vestibulum porttitor. Nulla facilisi. Sed a turpis eu lacus commodo
facilisis. Morbi fringilla, wisi in dignissim interdum, justo lectus sagittis dui, et
vehicula libero dui cursus dui. Mauris tempor ligula sed lacus. Duis cursus enim
ut augue. Cras ac magna. Cras nulla. Nulla egestas. Curabitur a leo. Quisque
egestas wisi eget nunc. Nam feugiat lacus vel est. Curabitur consectetuer.
    Suspendisse vel felis. Ut lorem lorem, interdum eu, tincidunt sit amet,
laoreet vitae, arcu. Aenean faucibus pede eu ante. Praesent enim elit, rutrum
at, molestie non, nonummy vel, nisl. Ut lectus eros, malesuada sit amet, fer-
mentum eu, sodales cursus, magna. Donec eu purus. Quisque vehicula, urna sed
ultricies auctor, pede lorem egestas dui, et convallis elit erat sed nulla. Donec
luctus. Curabitur et nunc. Aliquam dolor odio, commodo pretium, ultricies
non, pharetra in, velit. Integer arcu est, nonummy in, fermentum faucibus,
egestas vel, odio.
    Sed commodo posuere pede. Mauris ut est. Ut quis purus. Sed ac odio. Sed
vehicula hendrerit sem. Duis non odio. Morbi ut dui. Sed accumsan risus eget
odio. In hac habitasse platea dictumst. Pellentesque non elit. Fusce sed justo
eu urna porta tincidunt. Mauris felis odio, sollicitudin sed, volutpat a, ornare
ac, erat. Morbi quis dolor. Donec pellentesque, erat ac sagittis semper, nunc
dui lobortis purus, quis congue purus metus ultricies tellus. Proin et quam.
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
hymenaeos. Praesent sapien turpis, fermentum vel, eleifend faucibus, vehicula
eu, lacus.
    Pellentesque habitant morbi tristique senectus et netus et malesuada fames
ac turpis egestas. Donec odio elit, dictum in, hendrerit sit amet, egestas sed, leo.
Praesent feugiat sapien aliquet odio. Integer vitae justo. Aliquam vestibulum
fringilla lorem. Sed neque lectus, consectetuer at, consectetuer sed, eleifend ac,
lectus. Nulla facilisi. Pellentesque eget lectus. Proin eu metus. Sed porttitor.
In hac habitasse platea dictumst. Suspendisse eu lectus. Ut mi mi, lacinia sit
amet, placerat et, mollis vitae, dui. Sed ante tellus, tristique ut, iaculis eu,
malesuada ac, dui. Mauris nibh leo, facilisis non, adipiscing quis, ultrices a, dui.
    \nodrmstart Morbi luctus, wisi viverra faucibus pretium, nibh est placerat odio, nec com-
modo wisi enim eget quam. Quisque libero justo, consectetuer a, feugiat vitae,
porttitor eu, libero. Suspendisse sed mauris vitae elit sollicitudin malesuada.
Maecenas ultricies eros sit amet ante. Ut venenatis velit. Maecenas sed mi eget
dui varius euismod. Phasellus aliquet volutpat odio. Vestibulum ante ipsum \nodrmend
primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque sit
amet pede ac sem eleifend consectetuer. Nullam elementum, urna vel imperdiet
sodales, elit ipsum pharetra ligula, ac pretium ante justo a nulla. Curabitur
tristique arcu eu metus. Vestibulum lectus. Proin mauris. Proin eu nunc eu
urna hendrerit faucibus. Aliquam auctor, pede consequat laoreet varius, eros
tellus scelerisque quam, pellentesque hendrerit ipsum dolor sed augue. Nulla
nec lacus.
    Suspendisse vitae elit. Aliquam arcu neque, ornare in, ullamcorper quis,
commodo eu, libero. Fusce sagittis erat at erat tristique mollis. Maecenas
sapien libero, molestie et, lobortis in, sodales eget, dui. Morbi ultrices rutrum
lorem. Nam elementum ullamcorper leo. Morbi dui. Aliquam sagittis. Nunc
placerat. Pellentesque tristique sodales est. Maecenas imperdiet lacinia velit.
Cras non urna. Morbi eros pede, suscipit ac, varius vel, egestas non, eros.
Praesent malesuada, diam id pretium elementum, eros sem dictum tortor, vel
consectetuer odio sem sed wisi.
\end{document}

There will be problems when there are multiple rectangles to be excluded on the same page and for some reason the \EveryShipout does not operate on the first page. It will work on subsequent pages though. The randomized circles drawn are just an example, you can add any kind of randomized shape in the for loop, the seed ensures uniformity over different compilations. The code creates clipping rectangles using the y coordinates set by \nodrmstart and \nodrmend. The multiple rectangles on the same page issue, could be fixed by creating a list of pairs and iterating over those in the clipping path. It will not be trivial though. The resulting second page looks like this:

Obfuscated Page with rectangle left out

Note that the circles are drawn all the way down to the bottom of the page, since the \textheight is used to draw them.

5
  • This does not compile for me, and I had a friend check on a different distribution - it failed as well. Is the snippet exactly what compiles for you? The screenshot suggests that it works perfectly on your end...
    – Neith
    Nov 17, 2011 at 21:19
  • @Neith: Yes, I just copy-pasted it and it compiles perfectly. Are you or your friend getting any errors? Nov 18, 2011 at 8:21
  • Whoops, sorry, that was my fault (and my friend's, apparently) - I should update my packages more often. I'm using MikTeX and he uses TeX Live; he probably haven't updated packages in a while either.
    – Neith
    Nov 19, 2011 at 17:17
  • BTW, I noticed that the exclusion by \nodrmstart doesn't seem to work when I make paragraphs on the page - e.g. inserting one extra newline before "Pellentesque habitant morbi tristique" to make it a separate paragraph causes the protected region to be drawn on. I've decided to go with mbork's solution, as it's working for me so far.
    – Neith
    Nov 19, 2011 at 17:28
  • @Neith: That does seam to break it. I don't really understand why... If I draw the clipping path then the rectangle that should be drawn by the coordinates from \nodrmstart and \nodrmend isn't drawn at all. If you are happy with mbork's solution, I am not going to check into it further at this point. Nov 19, 2011 at 19:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .