10

Out of curiosity I looked up the code for \color in the xcolor library. And I found this:

\long\def\color@b@x#1#2#3%
 {\leavevmode
  \setbox\z@\hbox{\kern\fboxsep{\set@color#3}\kern\fboxsep}%
  \dimen@\ht\z@\advance\dimen@\fboxsep\ht\z@\dimen@
  \dimen@\dp\z@\advance\dimen@\fboxsep\dp\z@\dimen@
  {#1{#2\color@block{\wd\z@}{\ht\z@}{\dp\z@}\box\z@}}}

the main line that seems relevant is the last line:

#1{#2\color@block{\wd\z@}{\ht\z@}{\dp\z@}\box\z@}}

It seems this is just a another function call to another color.


Reading the docs a bit more I think \color is defined here:

\DeclareRobustCommand\color
 {\@ifnextchar[\@undeclaredcolor\@declaredcolor}

and then it gets complicated with two internal functions If the next character is [ it does one thing or else it does the other:

\def\@undeclaredcolor[#1]#2%
 {\begingroup
  \let\@@cls\@empty
  \XC@getmodclr12{#1}{#2}{}%
   {\ifblendcolors
      \ifx\colorblend\@empty\else
        \edef\@@mix{\expandafter\@gobble\colorblend}\@tempswafalse
        \XC@coremodel\@@mod\@@clr\@xcolor@{}{}\@@mod\@@clr
      \fi
    \fi
    \ifconvertcolorsU
      \edef\@@tmp{\XC@tgt@mod{\@@mod}}%
      \convertcolorspec\@@mod\@@clr\@@tmp\@@clr \let\@@mod\@@tmp
    \fi
    \ifmaskcolors
      \convertcolorspec\@@mod\@@clr\XC@mmod\@@clr
      \let\@@mod\XC@mmod
      \XC@inflate\@@mod\XC@mclr\@@clr\@@tmp
      \expandafter\XC@mul\@@tmp,\@@clr
    \fi
    \edef\@@tmp{\noexpand\XC@undeclaredcolor{\@@mod}{\@@clr}}%
    \expandafter\endgroup\@@tmp}}

and another function for declared colors:

\def\@declaredcolor#1%
 {\XC@edef\XC@@tmp{#1}\XC@@tstfalse
  \ifcase\XC@type\XC@@tmp\relax \XC@@tsttrue\or \relax\else
    \ifblendcolors\XC@@tsttrue\fi \ifmaskcolors\XC@@tsttrue\fi
    \ifconvertcolorsU\XC@@tsttrue\fi
  \fi
  \ifXC@@tst
    \expandafter\XC@declaredcolor\else
    \expandafter\XC@declaredc@lor\fi}

I merely want to understand how someting like {\color{blue!50!white} this is blue!} can be written manually

  • 1
    What do you mean 'manually'? The aim of the code in the end is to get to the appropriate special(s) depending on the engine in use. You can do that, of course, but most people regard it as rather tedious! – Joseph Wright Nov 11 '16 at 23:14
  • 1
    Also, xcolor has all of the mix-in business: perhaps we might start with the 'basic' color package version? – Joseph Wright Nov 11 '16 at 23:22
  • @JosephWright absolutely! i don't know a lot of how the TeX macros work, but since there are certain affects that I have found difficult to achieve, I have started learning all the sources myself. brb – john mangual Nov 11 '16 at 23:27
  • 1
    Speaking of xcolor definitions, I've always wondered why \textcolor is defined as macro:#1{->\@textcolor {#1}{, i.e. why it uses the #{ parameter syntax instead for two ordinary, undelimited arguments. – siracusa Nov 12 '16 at 8:54
  • 1
    @siracusa isn't the #1 suppose to hold a possible [optional] argument ? is seems from brief check that \textcolor will hand over to \color the check and handling for potential optional argument. – user4686 Nov 12 '16 at 12:18
15

The code you show at the top is the internals for \colorbox setting a box with a background colour which is why it calls \color internally. Other than that it is pretty hard to answer your question in this generality. The whole point of color and xcolor packages is to take a consistent user input and then generate whatever needs to be generated to produce color, so it depends if you are using dvips or dvipdfm or pdftex or xetex or ... different code is generated in each case. Start with texdoc color.dtx and read the documented sources of the color package, xcolor uses the same basic framework but vastly extended with the mixing syntax and more colour models.

\documentclass{article}
\usepackage{xcolor}
\begin{document}
\showoutput
{\color{blue!50!white} this is blue!}

\end{document}

with pdftex will show that that colour is achieved by

...\pdfcolorstack 0 push {0.5 0.5 1 rg 0.5 0.5 1 RG}
...\glue(\topskip) 3.05556
...\hbox(6.94444+0.0)x345.0, glue set 279.33325fil
....\hbox(0.0+0.0)x15.0
....\OT1/cmr/m/n/10 t
....\OT1/cmr/m/n/10 h
....\OT1/cmr/m/n/10 i
....\OT1/cmr/m/n/10 s
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/n/10 i
....\OT1/cmr/m/n/10 s
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/n/10 b
....\OT1/cmr/m/n/10 l
....\OT1/cmr/m/n/10 u
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 !
....\pdfcolorstack 0 pop

so

\pdfcolorstack 0 push {0.5 0.5 1 rg 0.5 0.5 1 RG}

and

\pdfcolorstack 0 pop

but if you just use the primitives nested latex colours would not work, and of course the document would only work with pdftex not latex+dvips or xetex etc. Dissasembling the output isn't the best way, both color and xcolor have fully documented sources if you need the full details.

  • 1
    I had once an issue (using dvipdfmx driver) and I concluded color was lacking some interface. \set@color will do \special {pdf:bcolor \current@color }\aftergroup \reset@color . In my context creating a group was no option. I ended up using directly \special{pdf:bcolor OrangeRed} and \special{pdf:ecolor}. There (afaict) is no interface for this in color. Issue: iterate \color{blue} A\par many times (129 times) then then dvipdfmx will complain dvipdfmx:warning: Color stack overflow. Just ignore. and colours will get wrong after that in the pdf document. – user4686 Nov 12 '16 at 10:52
  • 1
    in fact 127 times are enough in a minimal article document with page numbering (it produces 3 pages, and the third page number gets contaminated by the colour), now that I tested again. An interface of the type \startcolor/\stopcolor, not using groups, seems to be lacking. – user4686 Nov 12 '16 at 11:02
  • the reported issue regards also xetex. – user4686 Nov 12 '16 at 11:24
  • @jfbu well yes the code in xdvipdfmx and dvipdfmx is probably the same here. – David Carlisle Nov 12 '16 at 11:27
15

There are different aspects to this question, broadly:

  • How colour is implemented in TeX at a low level
  • How the color package macros converts a user level colour instruction into a low-level colour command
  • How the xcolor package extends color to give 'mix ins' and related effects

I'll tackled these areas separately. The question asks us about the user-level construct

{\color{blue!50!white} this is blue!}

and I will therefore use this or the simplified version

{\color{blue} this is blue!}

in the answer.


At a low level, TeX itself does not support colour at all. Rather, it leaves it to the driver, via the \special primitive and whatever form of special the driver requires. In a modern TeX set up, the drivers we tend to worry about are direct PDF production (pdfTeX/LuaTeX), dvips for the PostScript route from pdfTeX and (x)dvipdfmx for XeTeX and the DVI-to-PDF route from pdfTeX.

Each driver has it's own instruction and it's own colour notation to track. I'm going to focus on direct PDF production using pdfTeX for the answer. It has a primitive called \pdfcolorstack which needs a colour stack number and a colour description as greyscale, RGB or CMKY values. As we'll end up later with RGB, I'll go with that form:

\pdfcolorstack 0 push {0 0 1 rg 0 0 1 RG}
<Text here>
\pdfcolorstack 0 pop

will make the text blue. As you'll see, there are two colours to set in direct PDF mode: background and foreground. That's no universal so other driver code has to track such things 'by hand'. Also notice that the RGB values are given out of 100%, so here we've got full blue but no red or green.


That variability in driver code and the rather non-memorable form of colours is the reason most people rely on abstraction by the color package or a successor. If we use \tracingall with the color package we find that \color first looks for an optional [. As described in the color manual, the optional argument is a colour model, so one might have

\color[rgb]{0,0,1}

to specify blue without having pre-defined it. In the case where the optional argument is not found, the internal macro \@declaredcolor is chosen. It looks for a pre-defined colour specification with awkward name \\color@<argument>, so for us \\color@blue. Assuming that is found, it then uses that (which here is defined as 0 0 1 rg 0 0 1 RG) and writes the same low-level line as before.

The definitions of colours and the exact actions to take with them are defined by various driver-dependent files, so the same mechanism will give the correct underlying instruction for pdfTeX in PDF mode and classical dvips even though they need different low-level forms.


The xcolor package extends the above by allowing 'mix ins', where two or more colours are combined. Taking our blue!50!white example, this means we end up with the low-level instruction

\pdfcolorstack 0 push {0.5 0.5 1 rg 0.5 0.5 1 RG}

Notice that this is a linear combination of blue (0 0 1) and white (1 1 1). Using \tracingall you'll find that there is a lot more to 'do' here than in the color case. Fundamentally, though, what has to be done is

  • Grab the two arguments as before (optional [<model>] and mandatory <color spec>)
  • Assuming no <model>, break up the <color spec> into named colours and amounts
  • Do the maths to make the requested linear combination
  • Write the appropriate low-level code
  • 2
    The argument parsing, value look up and maths is 'lots of standard TeX programming', which it's hard to put into one short-ish focussed answer! – Joseph Wright Nov 12 '16 at 8:43

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.