7

I am trying to colour letters/words/strings with multiple bands of colour per string. It would look like the flag of Ireland/Russia/Germany is behind the text. I would like my final function to let me use the text as if it were normal (i.e, without a larger bounding box).

I've added an outlined sample which works as I want, which is like normal text. I also want it to be outlined like this but that seems easier anyway.

sample of outline vs. sample of rainbow text

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fadings}
\usepackage{graphicx}
\usepackage{pslatex}
\usepackage{xcolor}
\usepackage{pdfrender}
\usepackage{pst-text}
\usepackage{pst-grad}
\usepackage{calc}

\begin{document} \newcommand{\sample}{\bfseries sample} \textpdfrender{ TextRenderingMode=FillStroke, LineWidth=.2pt, LineJoinStyle=1, FillColor=pink } \sample \ works well with other text.% \newlength{\samplewidth} \newlength{\sampleheight} \newlength{\colourheight} \newlength{\bandYone} \newlength{\bandYtwo} \newlength{\bandYthree} \newlength{\bandYfour} {\setlength{\samplewidth}{\widthof{\sample}} \setlength{\sampleheight}{\totalheightof{\sample}} \setlength{\colourheight}{.3333333333\sampleheight} \setlength{\bandYone}{-.5\sampleheight} \setlength{\bandYtwo}{\bandYone} \addtolength{\bandYtwo}{\colourheight} \setlength{\bandYthree}{\bandYtwo} \addtolength{\bandYthree}{\colourheight} \setlength{\bandYfour}{\bandYthree} \addtolength{\bandYfour}{\colourheight}

\framebox{% \begin{tikzfadingfrompicture}[name=A] \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1, transparent!0, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \end{tikzfadingfrompicture} \begin{tikzfadingfrompicture}[name=B] \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1,transparent!0, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \end{tikzfadingfrompicture} \begin{tikzfadingfrompicture}[name=C] \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1,transparent!0, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \end{tikzfadingfrompicture} \begin{tikzpicture} \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1,thick, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \path[path fading=A,fill=red,fit fading=false] (-.5\samplewidth,\bandYone) rectangle (.5\samplewidth,\bandYtwo); \path[path fading=B,fill=green,fit fading=false] (-.5\samplewidth,\bandYtwo) rectangle (.5\samplewidth,\bandYthree); \pathpath fading=C,fill=yellow,fit fading=false rectangle (.5\samplewidth,\bandYfour); %\path[draw=blue] (-10,-1) rectangle (10,0); %\path[draw=red] (-10,0) rectangle (10,1); \end{tikzpicture} } %Framebox } does not work well as it adds space around the text. \end{document}

keymasta
  • 177
  • 1
    unrelated but don't use epsf to include graphics in latex in any document written since the 1980s, similarly pslatex (which I wrote) should not be used this century. – David Carlisle Nov 17 '21 at 22:38
  • I'm not even sure how that ended up in my preamble. I think it was included with the example I originally found, but then I didn't know whether I needed it or not. Thx for the tip, will delete. – keymasta Nov 18 '21 at 20:32
  • 1
    copying random preambles is a really bad habit, it just leads to convoluted code and hard to debug clashes, Always start from an empty preamble and only add packages that you need in the document. – David Carlisle Nov 18 '21 at 20:35
  • I got rid of the random stuff I had in there. – keymasta Nov 20 '21 at 22:34

3 Answers3

8

The key to keep the normal text position of a tikz node text ist to use baseline as an option in tikzpicture. To reduce the overall space use inner sep and outer sep as you like. You can also use different seperation for xand y if you want.

Based on the answer from hpekristiansen I've addeded the possibility to define any amount of colors larger or equal than two. It makes use of the colormap definition from pgfplots. You can use existing ones or define your own.

Contour with pdfrender seems not to work, so I used contour.

\documentclass{article}

\usepackage{tikz} \usetikzlibrary{calc} \usepackage{pgfplots} \usepackage{contour}

\pgfplotsset{colormap={ShadingColor}{color=(blue),color=(green),color=(yellow),color=(orange),color=(red)}}

% \TextShade{<colormap>}{<number of colors>}{<contour color>}{<text>} \newcommand{\TextShade}[4]{% \begin{tikzpicture}[baseline] \foreach \c in {1,2,...,#2}{ \pgfplotscolormapaccess[1:#2]{\c}{#1} \definecolor{colortemp}{rgb}{\pgfmathresult} \ifnum\c=1 \node[colortemp, anchor=base, inner xsep=0pt, inner ysep=.5pt, outer sep=0pt,draw=black] (n) at (0,0) {\contour{#3}{#4}}; \else \pgfmathparse{1-(\c-1)/#2} \clip let \p1=(n.south west), \p2=(n.north east), in (n.south west) rectangle (\x2,\y1+\pgfmathresult\y2-\pgfmathresult\y1);
\node[colortemp, anchor=base, inner xsep=0pt, inner ysep=.5pt, outer sep=0pt] {#4}; \fi } \end{tikzpicture}% }

\begin{document}

~\\Large This \TextShade{ShadingColor}{50}{black}{abcdefghijklmnopqrstuvwxyz} is a test.\ This \TextShade{viridis}{3}{black}{abcdefghijklmnopqrstuvwxyz} is a test.\ % viridis, hot, ... This \TextShade{viridis}{3}{blue}{abcdefghijklmnopqrstuvwxyz} is a test.\ This \TextShade{viridis}{3}{green}{abcdefghijklmnopqrstuvwxyz} is a test.\ This abcdefghijklmnopqrstuvwxyz is a test.\

\end{document}

multi color text

For another way to shade letters you can also take a look at Rainbow-colored one letter with tikz and xcolor.

mais
  • 475
  • This approach is really nice in that there is less code per piece of text. I wonder if it would be possible to make the text outlined, as in my first sample. When I tried to combine \pdftextrender with your function it fills the outline with the same colours, as opposed to black for example. Ideally the parameter for linewidth is measured the same as in \pdftextrender – keymasta Nov 20 '21 at 22:38
  • 1
    I've edited my answer. pdfrender seems not to work, so I used the contour package. – mais Nov 22 '21 at 07:40
  • contour sure makes the text bad :( no copy-paste or search cause there are 12 of everything. Also you can't adjust the line thickness. I wonder what route someone could go to get the best of all worlds. I read in the link that "If you are using \pdfliteral primitive of PDFTeX, then you can use \special{pdf:code ...} for dvipdfmx driver." Could something like this work here? [1] https://tex.stackexchange.com/questions/191201/understanding-what-contour-package-does – keymasta Dec 07 '21 at 22:09
7

enter image description here

You are adding space tokens from ends of lines, each one I commented out with %%% I also set \fboxsep to 0pt to get a tighter box.


\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fadings}
\usepackage{graphicx}
\usepackage{epsf} 
\usepackage{svg}
%\usepackage{contour}
\usepackage{pslatex}
\usepackage{xcolor}
\usepackage{pdfrender}
\usepackage{pst-text}
\usepackage{pst-grad}
\usepackage{calc}

\begin{document} \newcommand{\sample}{\bfseries sample} \textpdfrender{ TextRenderingMode=FillStroke, LineWidth=.2pt, LineJoinStyle=1, FillColor=pink } \sample \ works well with other text.% \newlength{\samplewidth} \newlength{\sampleheight} \newlength{\colourheight} \newlength{\bandYone} \newlength{\bandYtwo} \newlength{\bandYthree} \newlength{\bandYfour} {\setlength{\samplewidth}{\widthof{\sample}} \setlength{\sampleheight}{\totalheightof{\sample}} \setlength{\colourheight}{.3333333333\sampleheight} \setlength{\bandYone}{-.5\sampleheight} \setlength{\bandYtwo}{\bandYone} \addtolength{\bandYtwo}{\colourheight} \setlength{\bandYthree}{\bandYtwo} \addtolength{\bandYthree}{\colourheight} \setlength{\bandYfour}{\bandYthree} \addtolength{\bandYfour}{\colourheight}

\setlength\fboxsep{0pt} \framebox{% \begin{tikzfadingfrompicture}[name=A] \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1, transparent!0, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \end{tikzfadingfrompicture}%%% \begin{tikzfadingfrompicture}[name=B] \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1,transparent!0, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \end{tikzfadingfrompicture}%%% \begin{tikzfadingfrompicture}[name=C] \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1,transparent!0, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \end{tikzfadingfrompicture}%%% \begin{tikzpicture} \path[clip] (-.5\samplewidth,-.5\sampleheight) rectangle (.5\samplewidth,.5\sampleheight); \node[scale=1,thick, inner sep=0pt, outer sep=0pt] at (0,0) {\sample}; \path[path fading=A,fill=red,fit fading=false] (-.5\samplewidth,\bandYone) rectangle (.5\samplewidth,\bandYtwo); \path[path fading=B,fill=green,fit fading=false] (-.5\samplewidth,\bandYtwo) rectangle (.5\samplewidth,\bandYthree); \pathpath fading=C,fill=yellow,fit fading=false rectangle (.5\samplewidth,\bandYfour); %\path[draw=blue] (-10,-1) rectangle (10,0); %\path[draw=red] (-10,0) rectangle (10,1); \end{tikzpicture}%%% }%%% %Framebox } does not work well as it adds space around the text. \end{document}

David Carlisle
  • 757,742
7
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\newcommand{\sample}{%
\begin{tikzpicture}[baseline]
\node[orange, anchor=base, inner sep=0pt, outer sep=0pt] (n) {sample};
\clip let \p1 =(n.north east), in (n.south west) rectangle (\x1,0.5*\y1);          
\node[green, anchor=base, inner sep=0pt, outer sep=0pt] {sample};
\clip let \p1 =(n.north east), in (n.south west) rectangle (\x1,0.2*\y1);          
\node[red, anchor=base, inner sep=0pt, outer sep=0pt] {sample};
\end{tikzpicture}}
~\\
This \sample{} is a test.\\
This sample is a test.\\
\end{document}

Text with multi colored word

Edit: With arguments

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\newcommand{\sample}[5]{%
\begin{tikzpicture}[baseline]
\node[#3, anchor=base, inner sep=0pt, outer sep=0pt] (n) {sample};
\clip let \p1 =(n.north east), in (n.south west) rectangle (\x1,#5*\y1);          
\node[#2, anchor=base, inner sep=0pt, outer sep=0pt] {sample};
\clip let \p1 =(n.north east), in (n.south west) rectangle (\x1,#4*\y1);          
\node[#1, anchor=base, inner sep=0pt, outer sep=0pt] {sample};
\end{tikzpicture}}
~\\
This \sample{red}{green}{orange}{0.2}{0.5} is a test.\\
This sample is a test.\\
\end{document}