2

I'd like to move the definition of a color into a separate file for some reasons (cf forward in robust-externalize for details), but I don't know how to extract the definition of a color from its name. How could I do that?

I can think of two approaches:

  1. somehow (how?) get the rgb of the color. The main problem is that the color might be CMYK and I’m afraid to lose information on the color this way.
  2. somehow extract the parameters that were given to \colorlet and \definecolor

Importantly, I don't want to redefine \colorlet or \definecolor.

MWE:

\documentclass[]{article}

\usepackage{xcolor}

\definecolor{colorA}{rgb}{1,.5,0} \definecolor{colorB}{HTML}{AABBCC} \definecolor{colorC}{hsb:rgb/cmyk}{1,0,0/0,1,1,0} \colorlet{colorD}{blue} \colorlet{colorE}{red!50!blue}

% How to write this function \NewDocumentCommand{\extractColorCommand}{m}{% \texttt{\textbackslash definecolor{#1}{???}{???}}% } \begin{document}

\textcolor{colorA}{I am colorA}

\textcolor{colorB}{I am colorB}

\textcolor{colorC}{I am colorC}

\textcolor{colorD}{I am colorD}

\textcolor{colorE}{I am colorE}

You can define the above colors using:

\extractColorCommand{colorA}

\extractColorCommand{colorA}

\extractColorCommand{colorB}

\extractColorCommand{colorC}

\extractColorCommand{colorD}

\extractColorCommand{colorE} \end{document}

tobiasBora
  • 8,684
  • 4
    you are assuming that color are defined only with xcolor, but they can also be defined with color or with l3color or as spotcolor with colorspace. And why do you want only the rgb value? What about spot colors? – Ulrike Fischer Nov 06 '23 at 21:35
  • @UlrikeFischer Oh, I’d love a super-generic solution, but xcolor is, I guess, covering 99% of use cases, and for the remaining 1% I provide other solutions if needed. But l3color and spotcolors is definitely something that would be cool to support by default if it is not too hard, so I’ll wait before accepting the current answer. – tobiasBora Nov 06 '23 at 23:03
  • Please don't end lines like that. I know it is just an example, but it tells new users this is an appropriate way to do it. – cfr Nov 06 '23 at 23:58
  • @cfr Thanks for your edit, I’ve accepted. You mean the very last \ before the paragraph break? – tobiasBora Nov 07 '23 at 00:02
  • @tobiasBora I mean all of the \\. You shouldn't break lines that way outside special environments (e.g. tabular/array). – cfr Nov 07 '23 at 00:06
  • You don't need to accept my answer yet. Why not see if somebody can come up with something clever? – cfr Nov 07 '23 at 00:07
  • @cfr Oh really? What's wrong with this, and how should I create a new line? For instance here they say that \ creates a new line: https://tex.stackexchange.com/questions/27028/what-is-the-difference-between-newline-and – tobiasBora Nov 07 '23 at 00:11
  • @cfr Ok, let's try to see if someone has a better solution then ^^ – tobiasBora Nov 07 '23 at 00:23
  • See https://tex.stackexchange.com/a/82666/. The emphasis there is on using it at the end of a paragraph, though. – cfr Nov 07 '23 at 00:23
  • I think the thought is that it almost never makes sense to break a line mid-paragraph. In your case, you're really trying to make a non-paragraph, but telling LaTeX it is a paragraph. So it doesn't produce the problems of using it at the end of a paragraph, but it is still a bad habit. If nothing else, it is non-semantic markup. – cfr Nov 07 '23 at 00:28
  • @I’ve changed it, but I’m not so sure about the semantic argument in the sense that I understand a paragraph as a group of related concepts (sentences, list…): different paragraphs can therefore be put relatively far away since they do not directly relate, but the items of a single paragraph should be put next to each others to reflect the fact that they closely relate. And this difference is also reflected in LaTeX since it defines parskip allowing to separate paragraphs more (and setting \setlength{\parskip}{1cm}, \ looks very different from \par). HTML also defines p and br. – tobiasBora Nov 07 '23 at 00:39

2 Answers2

8

The first method works only for colours defined with xcolor. As Ulrike Fischer pointed out, this is not a general solution. The second works only for colours defined with l3color.

Caveat emptor ...

But if you know the colour is defined with xcolor (e.g. because you always define colours that way and this is your own code), you can use \extractcolorspec and/or \extractcolorspecs from the xcolor package to retrieve details of those colours.

\documentclass{article}
\usepackage{xcolor}
\colorlet{myblue}{blue!50!cyan}
\begin{document}
\extractcolorspec{myblue}{\mybluecmd}\mybluecmd

\extractcolorspecs{myblue}{\mybluemodel}{\mybluecmd}Model \mybluemodel, cmd \mybluecmd \end{document}

recovered colour specifications

Similarly, for colours defined using l3color, you can use one of the export functions.

\color_set:nn {myotherblue} { blue!50!black }

The following cycles through the various export options and uses \color_export:nnN to extract the appropriate colour information for myotherblue.

\clist_map_inline:nn { backend, space-sep-rgb, HTML, comma-sep-rgb, comma-sep-cmyk, space-sep-cmyk }
{
  \color_export:nnN {myotherblue} {#1} \l_tmpa_tl 
  #1: ~ \l_tmpa_tl \par
}

expl3: exported colour specs for l3color colour

Complete code:

\documentclass{article}
\usepackage{xcolor}
\colorlet{myblue}{blue!50!cyan}
\begin{document}
\extractcolorspec{myblue}{\mybluecmd}\mybluecmd

\extractcolorspecs{myblue}{\mybluemodel}{\mybluecmd}Model \mybluemodel, cmd \mybluecmd

\ExplSyntaxOn

\color_set:nn {myotherblue} { blue!50!black }

\clist_map_inline:nn { backend, space-sep-rgb, HTML, comma-sep-rgb, comma-sep-cmyk, space-sep-cmyk } { \color_export:nnN {myotherblue} {#1} \l_tmpa_tl #1: ~ \l_tmpa_tl \par } \ExplSyntaxOff

\end{document}

cfr
  • 198,882
  • Great, thanks a lot, exactly what I needed! (seems like I should have read further…) Good to know it is not as general as possible, so I’ll accept later in case someone gets a more generic solution, but it is already fairly good since xcolor is already fairly powerful. – tobiasBora Nov 06 '23 at 22:59
  • 1
    @tobiasBora I've added an example for l3color. I'm not sure you can get a general solution in the sense of a single function which can parse any colour and retrieve the specification. To do that, you'd need code which first figured out which framework to use in order to apply the corresponding method for retrieving the colour spec. I have no idea if that is even possible. – cfr Nov 06 '23 at 23:56
3

With testcolors environment you can print the color parameters in any format, but unlike \extractcolorspec you cannot assign that values to some command, so translate this to a new definition as:

\definecolor{mynewcolorA}{RGB}{255,128,0}

...is up to you.

But note that even a conversion rbg → RGB → rgb could change lighty the color definition because the decimals (e.g., 1,.5,0255,128,01,.50195,0).

Mwe

\documentclass[landscape]{article}
\usepackage{geometry}
\usepackage{xcolor}
\definecolor{colorA}{rgb}{1,.5,0}
\definecolor{colorB}{HTML}{AABBCC}
\definecolor{colorC}{hsb:rgb/cmyk}{1,0,0/0,1,1,0}
\colorlet{colorD}{blue}
\colorlet{colorE}{red!50!blue}
\begin{document}
\sffamily
\begin{testcolors}[RGB,rgb,HTML,cmyk,hsb]
\testcolor{colorA}
\testcolor{colorB}
\testcolor{colorC}
\testcolor{colorD}
\testcolor{colorE}
\end{testcolors}
\end{document}
Fran
  • 80,769