9

I’m trying to emulate in TikZ a title page which I’ve previously drawn in SVG. The image below is from the SVG version, where the shadowed text is achieved using a feGaussianBlur filter. But everything I’ve found regarding filters and shadows and such with TikZ seems not to apply to text.

Is there a way to achieve this result?

Current code (translated by hand from the SVG and adapted to my book layout):

\documentclass[11pt,extrafontsizes]{memoir}

\setstocksize{9in}{6in}
\settrimmedsize{\stockheight}{\stockwidth}{*}
\medievalpage[12]
\checkandfixthelayout

%\usepackage{fontspec}
%\newfontfamily\gingerfont{RM Ginger}
%\newcommand*{\ginger}[1]{\gingerfont\fontsize{#1}{#1}\selectfont}
\newcommand*{\ginger}[1]{\normalfont\fontsize{#1}{#1}\selectfont}

\usepackage{tikz}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc,positioning,decorations.text}
\tikzset{x=1in,y=1in}

\begin{document}
\thispagestyle{empty}
\begin{tikzpicture}[remember picture,overlay,shift={($ (current page.south west) + (0.5, 0.5) $)}]

  \node at (2.5, 7) [font=\ginger{31.5}, anchor=base] {Unshadowed Text};

  \draw[shift={(0, 5.75)}, decorate,
      decoration={text along path, text align=center,
      text={|\ginger{40.5}|The Long Title}}]
    (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
      .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);

  \node at (2.5, 6.125) [font=\ginger{31.5}, anchor=base] {of};

  \draw[shift={(0, 5)}, decorate,
      decoration={text along path, text align=center,
      text={|\ginger{81}|the Book}}]
    (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
      .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);

  \node at (2.5, 4.25) [font=\ginger{47.25}, anchor=base] {A. U. Thor};

  \node at (2.5, 3) [font=\ginger{31.5}, anchor=base] {More unshadowed text};

  \node at (2.5, 2.5) [font=\ginger{27}, anchor=base] {and some more};
\end{tikzpicture}
\end{document}

What the SVG version looks like: Example title page with SVG blur

6
  • (Yes, the example text overlaps in a not-pretty way. The actual title looks just fine.) Nov 12 '17 at 23:07
  • You can turn the text into a picture and manipulate it. For example, by using the text to define a shading or fading. Or you can do certain things to characters in text using the decorations.text library. But if you want Gaussian shadings, stick with a tool that gives you Gaussian shadings. Is there really any reason to redo this in TikZ?
    – cfr
    Nov 13 '17 at 0:21
  • The main reason for the reimplementation is that I’m not satisfied with the quality of the SVG-to-PDF transformation I get from Inkscape. The secondary reason is that I want to learn TikZ better. Nov 13 '17 at 1:48
  • 1
    Well, I don't think you'll get your Gaussian blur. Not unless you implement it directly using some plot of a function or something. (If that's even how it works.) You can maybe do something vaguely similar and hackish. However, note that the results may not print correctly or display correctly in all PDF viewers. (Some printers work better than others for this kind of thing; some PDF viewers work better than others. Transparency and shading affects are rather unpredictable.)
    – cfr
    Nov 13 '17 at 1:55
  • 1
    Applying a Gaussian blur using a graphics editor can be time consuming, so imagine how long it would take a dancing bear like TikZ to do it. Nov 13 '17 at 16:26
11

I guess my answer comes a little bit late, but I give it anyway. Who knows?

Some blurred text

I tried to produce the blurring effect using a double loop; thinking about one letter, the loops are moving it around circularly and outwardly.

The function forBlurring tries to adapt the size of the blurring effect to the size of the letter. The normal vs bold font should be considered also...

I tried to stick to your code. Since you use the text along path decoration, to be able to handle opacity, one must pass to text effects along path correspondingly. I did this in the blurring part of the code (the first part).

If you keep the parameters below, the compilation asks for some patience.

\documentclass[11pt, extrafontsizes]{memoir}

\newcommand*{\ginger}[1]{\normalfont\fontsize{#1}{#1}\selectfont}
\newcommand*{\bfginger}[1]{\bfseries\fontsize{#1}{#1}\selectfont}

\usepackage{xcolor}
\colorlet{blurColor}{black!75}

\usepackage{tikz}
\usetikzlibrary{math, calc, positioning, decorations.text}
\tikzset{x=1in, y=1in}

\begin{document}
\thispagestyle{empty}

\tikzmath{%
  integer \N;
  \N = 17; % 23;
  real \op, \tmp;
  \op = .025;
  function forBlurring(\i, \s) {
    return \i*\s/61;
  };
}
\begin{tikzpicture}[]
  \foreach \i in {.1, .3, .45, .6, .8}{%
    \foreach \j in {0, ..., \N}{%
      \tikzmath{ \tmp = forBlurring(\i, 41); }
      \path[shift={($(0, 5.25)+({\j/(\N+1)*360} : \tmp ex)$)}, decorate,
      decoration={%
        text effects along path, text align=center,
        text={The Long Title},
        text effects/.cd,
        characters={text along path, blurColor,
          opacity=\op, font=\bfginger{41}}
      }]
      (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
      .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);

      \node[font=\bfginger{41}, anchor=base, blurColor, opacity=\op]
      at ($(2.5, 5.15)+({\j/(\N+1)*360} : \tmp ex)$) {of};

      \tikzmath{ \tmp = forBlurring(\i, 61); }
      \path[shift={($(0, 3.5)+({\j/(\N+1)*360} : \tmp ex)$)}, decorate, 
      decoration={%
        text effects along path, text align=center,
        text={the Book},
        text effects/.cd,
        characters={text along path, blurColor,
          opacity=\op, font=\bfginger{61}}
      }]
      (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
      .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);

      \tikzmath{ \tmp = forBlurring(\i, 47); }
      \node[font=\ginger{47}, anchor=base, blurColor, opacity=\op]
      at ($(2.5, 2.5)+({\j/(\N+1)*360} : \tmp ex)$) {A. U. Thor};     
    }
  }
  
  \node at (2.5, 7) [font=\ginger{31}, anchor=base] {Unshadowed Text};

  \draw[shift={(0, 5.25)}, decorate,
  decoration={%
    text along path, text align=center,
    text={|\bfginger{41}|The Long Title}
  }]
  (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
  .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);

  \node at (2.5, 5.15) [font=\bfginger{41}, anchor=base] {of};
  
  \draw[shift={(0, 3.5)}, decorate, 
  decoration={%
    text along path, text align=center,
    text={|\bfginger{61}|the Book}
  }]
  (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
  .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);

  \node at (2.5, 2.5) [font=\ginger{47.25}, anchor=base] {A. U. Thor};

  \node at (2.5, 1.25) [font=\ginger{28}, anchor=base]
  {More unshadowed text};

  \node at (2.5, .75) [font=\ginger{28}, anchor=base]
  {and some more};
\end{tikzpicture}
2
  • Wow. Since I wrote the question, I’ve come to understand why the answer is probably “no”: blur is inherently a raster operation, and the TikZ graphics model is very much a vector model. (SVG blurs the distinction with filters and the like.) And then comes an answer like this, that beats TikZ into submission till it does what it shouldn’t be able to do. Beautiful. Aug 14 '20 at 10:45
  • 2
    My lot of compliments....
    – Sebastiano
    Aug 14 '20 at 11:58
6

Less hackish, perhaps:

Setting the Text Render mode (PDF operator Tr) to 2 which is "fill & stroke" (normal is 0 = fill-only), then gradually reducing the line width and the stroke colour (from white to black) while overlaying the text on itself many times. Note that the text is not moved around to create the blur.

The intensity of the blur effect depends on the initial line width used for stroking the glyph outlines: the larger the more intense. The example could be extended to use different values for different font sizes.

And yes, one shouldn't forget to set the graphics state parameter "line join" to 1, meaning "round" to avoid sharp corners. enter image description here

\documentclass[11pt,extrafontsizes,oneside]{memoir}

\newcommand*{\ginger}[1]{\normalfont\fontsize{#1}{#1}\selectfont}
\newcommand*{\bfginger}[1]{\bfseries\fontsize{#1}{#1}\selectfont}

\usepackage{tikz}
\usetikzlibrary{calc,decorations.text}
\tikzset{x=1in,y=1in}

\begin{document}\thispagestyle{empty}
\begin{center}
\begin{tikzpicture}
  \node at (2.5, 7) [font=\ginger{32}, anchor=base] {Unshadowed Text};
  
  \foreach \i in {0,1,...,100} {
    \pgfmathsetmacro{\lw}{8.0-\i*0.08} % line width
    \pgfmathsetmacro{\lc}{1.0-\i*0.01} % stroke colour
    \pdfliteral{q          % save graphics state
      1 j                  % line join "Round"
      \lw\space w          % line width
      2 Tr}                % text render mode: fill & stroke
      \path[shift={(0, 5.25)}, decorate,
          decoration={text along path, text align=center,
          text={|\bfginger{40}\pdfliteral{\lc\space G}|The Long Title}}]
        (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
          .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);
    
      \node at (2.5, 5.18) [font=\bfginger{32}, anchor=base] {\pdfliteral{\lc\space G}of};
    
      \path[shift={(0, 3.5)}, decorate,
          decoration={text along path, text align=center,
          text={|\bfginger{60}\pdfliteral{\lc\space G}|the Book}}]
        (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
          .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);
    \pdfliteral{Q}         % restore graphics state
  }  
  
  \node at (2.5, 2.5) [font=\ginger{46}, anchor=base] {A. U. Thor};
  
  \node at (2.5, 1.25) [font=\ginger{32}, anchor=base] {More unshadowed text};
  
  \node at (2.5, 0.75) [font=\ginger{32}, anchor=base] {and some more};
\end{tikzpicture}
\end{center}
\end{document}

This is a slightly improved example. Instead of directly typesetting the title page, we create an Opacity Mask (Fading, in TikZ parlance) in almost the same way as above. (The only difference: we vary the colour in the reverse direction from black to white, as black mask areas are fully transparent, white areas fully opaque.) This opacity mask allows us to combine arbitrary background and foreground colours.

enter image description here

\documentclass[11pt,extrafontsizes,oneside]{memoir}

\newcommand*{\ginger}[1]{\normalfont\fontsize{#1}{#1}\selectfont}
\newcommand*{\bfginger}[1]{\bfseries\fontsize{#1}{#1}\selectfont}

\usepackage{tikz}
\usetikzlibrary{calc,decorations.text}
\tikzset{x=1in,y=1in}

\pagestyle{empty}

\begin{document}
\pgfdeclarefading{titlemask}{%
  \begin{tikzpicture}[text=white,/pgf/decoration/text color=white] % default text colour --> fully opaque
    \node at (2.5, 7) [font=\ginger{32}, anchor=base] {Unshadowed Text};
    \foreach \i in {0,1,...,100} {
      \pgfmathsetmacro{\lw}{8.0-\i*0.08} % line width
      \pgfmathsetmacro{\lc}{\i*0.01} % stroke colour
      \pdfliteral{q          % save graphics state
        1 j                  % line join "Round"
        \lw\space w          % line width
        2 Tr}                % text render mode: fill & stroke
        \path[shift={(0, 5.25)}, decorate,
            decoration={text along path, text align=center,
            text={|\bfginger{40}\pdfliteral{\lc\space G}|The Long Title}}]
          (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
            .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);
        \node at (2.5, 5.18) [font=\bfginger{32}, anchor=base] {\pdfliteral{\lc\space G}of};
        \path[shift={(0, 3.5)}, decorate,
            decoration={text along path, text align=center,
            text={|\bfginger{60}\pdfliteral{\lc\space G}|the Book}}]
          (0, 0) .. controls (1, 0.5) and (1.625, 0.625) .. (2.5, 0.625)
            .. controls (3.375, 0.625) and (4, 0.5) .. (5, 0);
      \pdfliteral{Q}         % restore graphics state
    }  
    \node at (2.5, 2.5) [font=\ginger{46}, anchor=base] {A. U. Thor};
    \node at (2.5, 1.25) [font=\ginger{32}, anchor=base] {More unshadowed text};
    \node at (2.5, 0.75) [font=\ginger{32}, anchor=base] {and some more};
    % save corners and centre of the mask
    \pgfpointanchor{current bounding box}{south west}
    \pgfgetlastxy{\maskllx}{\masklly}\xdef\maskll{\maskllx,\masklly}
    \pgfpointanchor{current bounding box}{north east}
    \pgfgetlastxy{\maskurx}{\maskury}\xdef\maskur{\maskurx,\maskury}
    \pgfpointanchor{current bounding box}{center}
    \pgfgetlastxy{\maskcx}{\maskcy}\xdef\maskc{\maskcx,\maskcy}
  \end{tikzpicture}%
}

\begin{center}
\begin{tikzpicture}
\fill[scope fading=titlemask, fit fading=false,  % install mask on black rectangle
        fading transform={shift={(\maskc)}}] (\maskll) rectangle (\maskur);
\end{tikzpicture}
\end{center}

\newpage\pagecolor{yellow!10}

\begin{center}
\begin{tikzpicture}
\fill[scope fading=titlemask, fit fading=false, fill=red!80!black, % ditto, but red rectangle
        fading transform={shift={(\maskc)}}] (\maskll) rectangle (\maskur);
\end{tikzpicture}
\end{center}
\end{document}
3
  • 2
    Also for you my sincere compliments. Very nice.
    – Sebastiano
    Aug 14 '20 at 21:50
  • 2
    @Sebastiano you are wrong. It is very nice. 🤣
    – manooooh
    Aug 15 '20 at 6:33
  • 1
    @manooooh ihhihihi :-)...No...:) LOL.
    – Sebastiano
    Aug 15 '20 at 7:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.