6

In TikZ/PGF, we can obtain the current line width using \pgflinewidth. Unfortunatelly there is no (as far as I know) \pgfstrokecolor, \pgffillcolor, \pgfstrokeopacity and \pgffillopacity.

My main question is : Is there some way to recover the current draw and fill color ?

I know that the last color set by \color can be recovered with \colorlet{saved}{.}, because dot represent the last color. And this can be used when we directly set the color as a style, like in \draw[red] ... (see the code).

I've tried to hack \pgfsetstrokecolor, \pgfsetfillcolor and \pgfsetcolor in a way to save the last call ... but without success.

In the following code I'm looking for some trick to save the colors in a way to be able to reuse them in another layer.

\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}

\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}

\begin{document}
  \begin{tikzpicture}[green, draw=red, ultra thick, fill=yellow, text=purple]
    \filldraw (-.5,-.5) rectangle +(1,1) node[midway]{A};
    \pgfmathsetlengthmacro{\savedpgflinewidth}{\pgflinewidth}
    \colorlet{saved}{.}
    \def\pgfstrokecolor{red} % <- to be replaced by \strokecolorlet
    \def\pgffillcolor{yellow} % <- to be replaced by \fillcolorlet

    \begin{pgfonlayer}{foreground}
      \draw (0,0) rectangle +(1,1) node[midway]{B};
      \color{saved} % <- restore the color set by \color{green}
      \pgfsetlinewidth{\savedpgflinewidth} % <- restore the line width
      \draw (.5,.5) rectangle +(1,1) node[midway]{C};
      \pgfsetstrokecolor{\pgfstrokecolor} % <- restore the draw color
      \pgfsetfillcolor{\pgffillcolor} % <- restore the fill color
      \filldraw (1,1) rectangle +(1,1) node[midway]{D};
    \end{pgfonlayer}

    \filldraw (1.5,1.5) rectangle +(1,1) node[midway]{E}; % <- line width reset after pgfonlayer !
  \end{tikzpicture}
\end{document}

enter image description here

Note 1: In the following code we can see that the line width is reset after the use of pgfonlayer. Is this a bug or a (documented) feature ?

Note 2: In a strange way the text color survive the layer change, but not the other colors, neither the line width.

Note 3: I have the impression that \pgfsetcolor is not used by TikZ, instead \color is used. If this is the case, why ?


EDIT : The code above is just a working example. I don't want to solve this particular case without recovering the colors.

  • The simple way is the declarative way: use pgfkeys and its .style handler to store your preferences (color, line width, etc.) and to apply them multiple times. – Paul Gaborit Dec 21 '14 at 17:49
  • The reason why you can't have this in the high-level form is because red is ambiguous depending on the color model etc. also colormixins make it more difficult but if you are happy with low level you can read of the softer versions from \color@pgfstrokecolor – percusse Dec 21 '14 at 19:51
  • @percusse this looks very promising ! Could you make an answer please. I've tried without success. I came to look at pgfcoregraphicstate.code.tex and it is used always inside a long long sequence of \expandafter that I can't understand ;) – Kpym Dec 21 '14 at 21:31
6

Here is a conceptual way of doing it. I think there are a lot of things to improve (less macros because you only need the last two items in the color description, proper expansion control, possibility of custom macro name) but I didn't have time. I think you can take it from here.

\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}
\makeatletter
\tikzset{get stroke color/.code={%
    \expandafter\global% Jump over, now we have \global
    \expandafter\let% Jump over now we have \global\let
    \expandafter\pgfsavedstrokecolor% Jump we have \global\let\pgf...
    \csname\string\color@pgfstrokecolor\endcsname% Finally expand this and put it at the end 
    },                                           % \global\let\pgf...{} in expanded form 
    restore stroke color/.code={\pgf@setstrokecolor#1},
}


\begin{document}
  \begin{tikzpicture}[green, draw=yellow!20!blue, ultra thick, fill=yellow, text=purple]
    \tikzset{get stroke color}% <-- Gets the drive-dependent low-level desc of y!20!b
    \show\pgfsavedstrokecolor% <-- Look at the log
    \filldraw (0,0) rectangle +(1,1) node[midway]{A};
    \pgfsetstrokecolor{orange} % <-- Change the drawing color to orange
    \draw (0.5,0.5) rectangle +(1,1) node[midway]{B}; % <-- Draw something to verify
    \tikzset{restore stroke color/.expand once=\pgfsavedstrokecolor} % <-- Restore it back
    \draw (1,1) rectangle +(1,1) node[midway]{C}; % <-- Verify
  \end{tikzpicture}
\end{document}

enter image description here

  • Thanks a lot. This is fantastic. I have some questions : 1) in the same way I can use \color@pgffillcolor, but I can't find the equivalent values for opacity. Have you an idea ? 2) In the code of my quastion if I put \tikzset{get stroke color} as first line, it works fine, but if I put it after the \filldraw it doesn't work. Any Idea ? 3) [not important] Why we can't use directly \color@pgfstrokecolor ? – Kpym Dec 22 '14 at 14:24
  • @Kpym Bah, I knew it was to good to be true off-the-shelf. I'll check again. – percusse Dec 23 '14 at 1:12
  • If I use \tikz@options just before \tikzset{get stroke color} it works. But I can't use it anywhere (for example in pic). – Kpym Dec 23 '14 at 17:05
  • @Kpym I've checked a bit again. If you give the option get stroke color to \filldraw it works again for your question 2. So that means we have to be in the same scope as the path commands. Can you try if there are other weirdnesses? – percusse Jan 4 '15 at 1:53
  • Thanks again! For the moment it looks ok for me. If I find another drawback, I'll be back here ;) – Kpym Jan 4 '15 at 10:38
1

The simple way is the declarative way: use pgfkeys and its .style handler to store your preferences (color, line width, etc.) and to apply them multiple times.

enter image description here

\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}

\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}

\begin{document}
\tikzset{my preferecences/.style={green, draw=red, ultra thick,fill=yellow, text=purple}}
\begin{tikzpicture}[my preferecences]
    \filldraw (-.5,-.5) rectangle +(1,1) node[midway]{A};
    \begin{pgfonlayer}{foreground}
      \begin{scope}[my preferecences]
      \draw (0,0) rectangle +(1,1) node[midway]{B};
      \draw (.5,.5) rectangle +(1,1) node[midway]{C};
      \filldraw (1,1) rectangle +(1,1) node[midway]{D};
      \end{scope}
    \end{pgfonlayer}

    \filldraw (1.5,1.5) rectangle +(1,1) node[midway]{E}; % <- line width reset after pgfonlayer !
  \end{tikzpicture}
\end{document}
  • Thanks for your answer. But this is not my question. I know how to use styles. This is a simple working example. I want to know if I can recover the current color. I want to define a style that can be used in any path by recovering the color and drawing something on another layer. – Kpym Dec 21 '14 at 18:01
  • I came to edit my question to precise that I don't want a solution without 'traversing' the color from one layer to another. Sorry if my question was not clear. – Kpym Dec 21 '14 at 18:08

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.