72

I recently asked a question on creating a torn paper effect. JLdiaz provided an absolutely beautiful answer, which I have used (with a very minor modification) to indicate the way in which a document is being cut up into sections by a program:

enter image description here

[JLDiaz's original had flat top edges; I essentially copied the method he used for the bottoms and wrapped it around the -- (A.north east) in his source to get torn top edges as well as bottom edges.]

This is far better than anything I thought achievable, but there is a tweak that would make it even better --- in fact, it's taken from a comment on JLDiaz's website. Would it be possible to make the torn edges of the adjacent 'pieces of torn paper' line up, so that the bottom of 58 matches the top of 59 (and so on)?

Final result:

enter image description here

3
  • 9
    You can get identical "random" lines by using the same seed. See tex.stackexchange.com/questions/70578/… Dec 10, 2012 at 15:50
  • That's very slick. I was thinking you'd have to somehow 'save' the curve. Now AFAICS the main problem is that filling isn't going to work properly unless the top edge is L->R and the bottom edge R->L (or vice versa) -- but presumably some kind of rotation can deal with that...
    – Mohan
    Dec 10, 2012 at 16:03
  • How did you get numbering effect on right side? Feb 5, 2016 at 18:39

2 Answers 2

58

UPDATE:

See the section "The final solution".


I was already working in the idea of resetting the random seed, but it alas, is easier said than done :-(

If you reset the random seed before drawing each border, you get the "same" random border in all your fragments, which is not nice. You want randomness in each new bottom border, but exactly the same randomness in the next top border. In order to get this, you need a global counter which is increased in each "paper fragment", and which is used as seed for the bottom border.

It is neccesary to use \pgfextra to be able of setting the seed in the middle of the path (i.e: between top and bottom borders).

In addition, there is the problem that both paths (top and bottom) have to be drawn in the same direction in order to get the same contour.

I managed to do all this without filling the resulting frame, but using only the drawn edges. However, when fill options are activated, all comes wrong. There are my current attempts:

\documentclass[a5paper]{article}
\usepackage{lipsum}   % To generate test text
\usepackage{framed}
\usepackage{tikz}
\usepackage[margin=1cm]{geometry}% for screen preview
\usetikzlibrary{decorations.pathmorphing,calc,shadows.blur,shadings}

\newcounter{mathseed}
\setcounter{mathseed}{3}
\pgfmathsetseed{\arabic{mathseed}} % To have predictable results
% Define a background layer, in which the parchment shape is drawn
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

% This is the base for the fractal decoration. It takes a random point between the start and end, and
% raises it a random amount, thus transforming a segment into two, connected at that raised point
% This decoration can be applied again to each one of the resulting segments and so on, in a similar
% way of a Koch snowflake.
\pgfdeclaredecoration{irregular fractal line}{init}
{
  \state{init}[width=\pgfdecoratedinputsegmentremainingdistance]
  {
    \pgfpathlineto{\pgfpoint{random*\pgfdecoratedinputsegmentremainingdistance}{(random*\pgfdecorationsegmentamplitude-0.02)*\pgfdecoratedinputsegmentremainingdistance}}
    \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}}
  }
}

% define some styles
\tikzset{
   paper/.style={draw, fill=none},
   irregular border/.style={decoration={irregular fractal line, amplitude=0.2},
           decorate,
     },
   ragged border/.style={ decoration={random steps, segment length=7mm, amplitude=2mm},
           decorate,
   }
}
\def\tornpaper#1{%
\tikz{
  \node[inner sep=1em] (A) {#1};  % Draw the text of the node
  \begin{pgfonlayer}{background}  % Draw the shape behind
  \fill[paper] % recursively decorate the bottom border
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}\addtocounter{mathseed}{1}}%
      { decorate[irregular border]{decorate{decorate{decorate{decorate[ragged border]{
        (A.north west) -- (A.north east)
      }}}}}}
      (A.north west) -- (A.south west)
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}}%
      {decorate[irregular border]{decorate{decorate{decorate{decorate[ragged border]{
      -- (A.south east)
      }}}}}}
      -- (A.north east) (A.north west) -- cycle;
  \end{pgfonlayer}}
}

\begin{document}
\noindent
\tornpaper{
\parbox{.9\textwidth}{\lipsum[11]}
}

\noindent
\tornpaper{
\parbox{.9\textwidth}{\lipsum[15]}
}

\noindent
\tornpaper{
\parbox{.9\textwidth}{\lipsum[5]}
}
\end{document}

Result

UPDATE:

In order to fill the piece of paper with a background, it is not possible to draw both top and bottom borders in the same direction (eg. left to right). So the solution involves drawing one piece of paper visiting its corners in clockwise direction, and the following one in counter-clockwise direction. I use the counter mathseed and draw in one direction or the other based on \isodd{mathseed}.

The final solution

This is my final code:

\documentclass[a5paper]{article}
\usepackage{lipsum}   % To generate test text
\usepackage{framed}
\usepackage{ifthen}
\usepackage{tikz}
\usepackage[margin=1cm]{geometry}% for screen preview
\usetikzlibrary{decorations.pathmorphing,calc,shadows.blur,shadings}

\newcounter{mathseed}
\setcounter{mathseed}{3}
\pgfmathsetseed{\arabic{mathseed}} % To have predictable results
% Define a background layer, in which the parchment shape is drawn
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

% This is the base for the fractal decoration. It takes a random point between the start and end, and
% raises it a random amount, thus transforming a segment into two, connected at that raised point
% This decoration can be applied again to each one of the resulting segments and so on, in a similar
% way of a Koch snowflake.
\pgfdeclaredecoration{irregular fractal line}{init}
{
  \state{init}[width=\pgfdecoratedinputsegmentremainingdistance]
  {
    \pgfpathlineto{\pgfpoint{random*\pgfdecoratedinputsegmentremainingdistance}{(random*\pgfdecorationsegmentamplitude-0.02)*\pgfdecoratedinputsegmentremainingdistance}}
    \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}}
  }
}


% define some styles
\tikzset{
   paper/.style={draw=black!3, blur shadow, every shadow/.style={opacity=1, black}, shade=bilinear interpolation,
                 lower left=black!10, upper left=black!5, upper right=white, lower right=black!5, fill=none},
   irregular border/.style={decoration={irregular fractal line, amplitude=0.2},
           decorate,
     },
   ragged border/.style={ decoration={random steps, segment length=7mm, amplitude=2mm},
           decorate,
   }
}

\def\tornpaper#1{%
\ifthenelse{\isodd{\value{mathseed}}}{%
\tikz{
  \node[inner sep=1em] (A) {#1};  % Draw the text of the node
  \begin{pgfonlayer}{background}  % Draw the shape behind
  \fill[paper] % recursively decorate the bottom border
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}\addtocounter{mathseed}{1}}%
      {decorate[irregular border]{decorate{decorate{decorate{decorate[ragged border]{
        (A.north west) -- (A.north east)
      }}}}}}
      -- (A.south east)
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}}%
      {decorate[irregular border]{decorate{decorate{decorate{decorate[ragged border]{
      -- (A.south west)
      }}}}}}
      -- (A.north west);
  \end{pgfonlayer}}
}{%
\tikz{
  \node[inner sep=1em] (A) {#1};  % Draw the text of the node
  \begin{pgfonlayer}{background}  % Draw the shape behind
  \fill[paper] % recursively decorate the bottom border
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}\addtocounter{mathseed}{1}}%
      {decorate[irregular border]{decorate{decorate{decorate{decorate[ragged border]{
        (A.north east) -- (A.north west)
      }}}}}}
      -- (A.south west)
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}}%
      {decorate[irregular border]{decorate{decorate{decorate{decorate[ragged border]{
      -- (A.south east)
      }}}}}}
      -- (A.north east);
  \end{pgfonlayer}}
}}

\begin{document}
\noindent
\tornpaper{
\parbox{.9\textwidth}{\lipsum[11]}
}

\noindent
\tornpaper{
\parbox{.9\textwidth}{\lipsum[15]}
}

\noindent
\tornpaper{
\parbox{.9\textwidth}{\lipsum[5]}
}
\end{document}

And the result:

Final result

Second update

As Mohan noticed in a comment, the above solution introduces an assymetry: "cloudy" papers alternate with "spiky" ones. The reason behind is that the algorithm that draws the fractal border tends to produce "spikes" towards its right (in the advance direction), and "cloud borders" towards its left. So, a box drawn in clockwise direction would have a "cloudy" aspect, while one drawn in counterclockwise direction would have a "spiky" aspect.

The assymetry can be make less apparent if the bottom border is drawn with a negative amplitude (which reverses the side towards the spikes appear). This is easy to achieve by defining two irregular border styles, which are used alternatively. These are the modificactions to the above code:

% define some styles
\tikzset{
   paper/.style={draw=black!10, blur shadow, every shadow/.style={opacity=1, black}, shade=bilinear interpolation,
                 lower left=black!10, upper left=black!5, upper right=white, lower right=black!5, fill=none},
   irregular cloudy border/.style={decoration={irregular fractal line, amplitude=0.2},
           decorate,
     },
   irregular spiky border/.style={decoration={irregular fractal line, amplitude=-0.2},
           decorate,
     },
   ragged border/.style={ decoration={random steps, segment length=7mm, amplitude=2mm},
           decorate,
   }
}
\tikz{
  \node[inner sep=1em] (A) {#1};  % Draw the text of the node
  \begin{pgfonlayer}{background}  % Draw the shape behind
  \fill[paper] % recursively decorate the bottom border
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}\addtocounter{mathseed}{1}}%
      {decorate[irregular cloudy border]{decorate{decorate{decorate{decorate[ragged border]{
        (A.north west) -- (A.north east)
      }}}}}}
      -- (A.south east)
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}}%
      {decorate[irregular spiky border]{decorate{decorate{decorate{decorate[ragged border]{
      -- (A.south west)
      }}}}}}
      -- (A.north west);
  \end{pgfonlayer}}
}{%
\tikz{
  \node[inner sep=1em] (A) {#1};  % Draw the text of the node
  \begin{pgfonlayer}{background}  % Draw the shape behind
  \fill[paper] % recursively decorate the bottom border
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}\addtocounter{mathseed}{1}}%
      {decorate[irregular spiky border]{decorate{decorate{decorate{decorate[ragged border]{
        (A.north east) -- (A.north west)
      }}}}}}
      -- (A.south west)
     \pgfextra{\pgfmathsetseed{\arabic{mathseed}}}%
      {decorate[irregular cloudy border]{decorate{decorate{decorate{decorate[ragged border]{
      -- (A.south east)
      }}}}}}
      -- (A.north east);
  \end{pgfonlayer}}
}}

Resulting in:

Result

10
  • 1
    @Mohan I updated my answer with a solution for this problem.
    – JLDiaz
    Dec 10, 2012 at 17:37
  • 3
    Very nice answer! You may contribute with it on texample.net/tikz/examples
    – Tobi
    Dec 10, 2012 at 17:57
  • 2
    Oh, also: I really think this is worth making into a package!
    – Mohan
    Dec 10, 2012 at 18:28
  • 5
    I second @Tobi; you should consider sending your nice answer to TeXample.net (and even producing a package.) Dec 10, 2012 at 18:42
  • 6
    Since version 3.0, shade=bilinear interpolation should be shading=bilinear interpolation.
    – Clément
    Feb 4, 2015 at 23:51
11

Simply turning the direction of the path should work:

\documentclass[]{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}

\begin{tikzpicture}
\draw[fill=gray]
(0,0)--(0,1) 
\pgfextra{\pgfmathsetseed{15}}
decorate[decoration={random steps,segment length=0.2cm,amplitude=.1cm}]
{-- (10,1)} -- (10,0) 
\pgfextra{\pgfmathsetseed{10}}
decorate[decoration={random steps,segment length=0.2cm,amplitude=.1cm}]
{-- (0,0)};
\end{tikzpicture}

\begin{tikzpicture}
\draw[fill=gray]
(10,1)
\pgfextra{\pgfmathsetseed{10}}
decorate[decoration={random steps,segment length=0.2cm,amplitude=.1cm}]
{-- (0,1)}
 --(0,0)
\pgfextra{\pgfmathsetseed{18}}
decorate[decoration={random steps,segment length=0.2cm,amplitude=.1cm}]
{-- (10,0)} 
 --(10,1);
\end{tikzpicture}

\begin{tikzpicture}
\draw[fill=gray]
(0,0)--(0,1)
\pgfextra{\pgfmathsetseed{18}}
decorate[decoration={random steps,segment length=0.2cm,amplitude=.1cm}]
{-- (10,1)} -- (10,0)
\pgfextra{\pgfmathsetseed{15}}
decorate[decoration={random steps,segment length=0.2cm,amplitude=.1cm}]
{-- (0,0)};
\end{tikzpicture}

\end{document}

You must log in to answer this question.

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