colo-new.mkii / last modification: 2008-10-04 14:57
%D \module
%D   [       file=colo-ini,
%D        version=1997.04.01,
%D          title=\CONTEXT\ Color Macros,
%D       subtitle=Initialization,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\unprotect

\chardef\colorversion=1

%D Color support is not present in \TEX. Colorful output can
%D however be accomplished by using specials. This also means
%D that this support depends on the \DVI\ driver used. At the
%D moment this module was written, still no decent standard on
%D color specials has been agreed upon. We therefore decided to
%D implement a mechanism that is as independant as possible of
%D drivers.
%D
%D Color support shares with fonts that is must be implemented
%D in a way that permits processing of individual \DVI\ pages.
%D Furthermore it should honour grouping. The first condition
%D forces us to use a scheme that keeps track of colors at
%D page boundaries. This can be done by means of \TEX's
%D marking mechanism (\type{\mark}).
%D
%D When building pages, \TEX\ periodically looks at the
%D accumulated typeset contents and breaks the page when
%D suitable. At that moment, control is transfered to the
%D output routine. This routine takes care of building the
%D pagebody and for instance adds headers and footers. The page
%D can be broken in the middle of some colored text, but
%D headers and footers are often in black upon white or
%D background. If colors are applied there, they definitely
%D are used local, which means that they don't cross page
%D borders.
%D
%D Boxes are handled as a whole, which means that when we
%D apply colors inside a box, those colors don't cross page
%D boundaries, unless of course boxes are split or unboxed.
%D Especially in interactive texts, colors are often used in
%D such a local way: in boxes (buttons and navigational tools)
%D or in the pagebody (backgrounds).
%D
%D So we can distinguish local colors, that don't cross
%D pages from global colors, of which we can end many pages
%D later. The color macros will treat both types in a different
%D way, thus gaining some speed.
%D
%D This module also deals with gray scales. Because similar
%D colors can end up in the same gray scale when printed in
%D black and white, we also implement a palet system that deals
%D with these matters. Because of fundamental differences
%D between color and gray scale printing, in \CONTEXT\ we also
%D differ between these. For historic reasons |<|we first
%D implemented gray scales using patterns of tiny periods|>|
%D and therefore called them {\em rasters}. So don't be
%D surprised if this term shows up.

%D \macros
%D   {definecolor}
%D
%D We will enable users to specify colors in \cap{RGB} and
%D \cap{CMYK} color spaces or gray scales using
%D
%D \showsetup{definecolor}
%D
%D For example:
%D
%D \starttyping
%D \definecolor [SomeKindOfRed] [r=.8,g=.05,b=.05]
%D \stoptyping
%D
%D Such color specifications are saved in a macro in the
%D following way:
%D
%D \starttyping
%D \setvalue{\??cr name}{R:r:g:b}
%D \setvalue{\??cr name}{C:c:m:y:k}
%D \setvalue{\??cr name}{S:s}
%D \stoptyping
%D
%D Gray scales are specified with the \type{s} parameter,
%D where the \type {s} is derived from {\em screen}.
%D
%D Starting with \PDF\ 1.4 (2001) \CONTEXT\ supports
%D transparent colors. The transparency factor is represented
%D by a \type {t} and the transparency method by an \type {a}
%D (alternative). Later we will implement more control
%D (probably by symbolic methods. So, currently the data is
%D stored as follows:
%D
%D \starttyping
%D \setvalue{\??cr name}{R:r:g:b:a:t}
%D \setvalue{\??cr name}{C:c:m:y:k:a:t}
%D \setvalue{\??cr name}{S:s:a:t}
%D \stoptyping

% r g b   : rbg
% c m y k : cmyk
% s       : gray
% p n d f : spot
% h       : hexadecimal
% t a     : transparency
% e       : equivalent (spotcolors)

\def\@@cl@@z{0}
\def\@@cl@@o{1}

\def\@@resetcolorparameters
  {\let\@@cl@@r\@@cl@@z \let\@@cl@@g\@@cl@@z \let\@@cl@@b\@@cl@@z
   \let\@@cl@@c\@@cl@@z \let\@@cl@@m\@@cl@@z \let\@@cl@@y\@@cl@@z \let\@@cl@@k\@@cl@@z
   \let\@@cl@@s\@@cl@@z
   \let\@@cl@@p\@@cl@@o \let\@@cl@@n\empty \let\@@cl@@d\empty \let\@@cl@@f\@@cl@@o
   \let\@@cl@@h\empty
   \let\@@cl@@e\empty
   \let\@@cl@@t\@@cl@@z \let\@@cl@@a\@@cl@@z}

\@@resetcolorparameters

\def\@@cl@@A{\@@cl@@a} % a hook for symbolic conversion, see below

%D Handling a few nested \type{\cs}'s is no problem (\type
%D {\@EA\@EAEAEA\@EA}) but we need a full expansion, so I
%D tried one of the fully expandable primitives using a sort
%D of delimited thing. I tried \type {\number} first, but this
%D does not work, but \type {\romannumeral} does. Actually,
%D \type{\romannumeral0} returns nothing, so it's a perfect
%D candidate for this kind of hackery. This reminds me that I
%D have to look into David Kastrup's Euro\TeX\ 2002 article
%D because he is using \type {\romannumeral} for loops
%D (repetitive \quote {m} stuff).

% \def\x{\y}\def\y{\z}\def\z{0:1:1:1}
%
% \def\bla #1:#2:#3\end{}
%
% \@EA\bla\romannumeral\x\end

\def\colorXpattern{0S:\@@cl@@z:\@@cl@@z:\@@cl@@z}
\def\colorZpattern{0S:\@@cl@@z:\@@cl@@A:\@@cl@@t}
\def\colorSpattern{0S:\@@cl@@s:\@@cl@@A:\@@cl@@t}
\def\colorCpattern{0C:\@@cl@@c:\@@cl@@m:\@@cl@@y:\@@cl@@k:\@@cl@@A:\@@cl@@t}
\def\colorRpattern{0R:\@@cl@@r:\@@cl@@g:\@@cl@@b:\@@cl@@A:\@@cl@@t}

%def\colorPpattern{0P:\@@cl@@n:\@@cl@@p:\@@cl@@A:\@@cl@@t}

\def\colorPpattern{0P:\@@cl@@n:\@@cl@@f:\@@cl@@d:\@@cl@@p:\@@cl@@A:\@@cl@@t}

%D The extra 0 catches empty colors specs (needed for the
%D \type {\MPcolor} and \type {\PDFcolor} conversion (\type
%D {\@@cr} equals \type {\relax}!).

\def\handlecolorwith#1{\@EA#1\romannumeral0}

%D Next comes the main definition macro.

\def\dodefinecolor      {\dododefinecolor\relax   \setvalue \setevalue1}
\def\dodefineglobalcolor{\dododefinecolor\doglobal\setgvalue\setxvalue1}
\def\dodefinenamedcolor {\dododefinecolor\doglobal\setvalue \setevalue0}

\def\dododefinecolor#1#2#3#4[#5][#6]% #2==set(g)value #3==set[e|x]value
  {#1\addtocommalist{#5}\colorlist % optional
   \doifassignmentelse{#6}
     {\@@resetcolorparameters
      \getparameters[\??cl @@][#6]%
      \ifx\@@cl@@h\empty
        \doifelse{\@@cl@@r\@@cl@@g\@@cl@@b}{\@@cl@@z\@@cl@@z\@@cl@@z}
          {\doifelse{\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k}{\@@cl@@z\@@cl@@z\@@cl@@z\@@cl@@z}
             {\doifelse\@@cl@@s\@@cl@@z
                {\showmessage\m!colors8{{[#6]},#5}%
                 #3{\??cr#5}{\colorZpattern}}
                {#3{\??cr#5}{\colorSpattern}}}
             {#3{\??cr#5}{\colorCpattern}}}
          {#3{\??cr#5}{\colorRpattern}}%
      \else
        \setxvalue{\??cr#5}{\colorHpattern}%
      \fi
      % new: e=external spot color name
      \ifx\@@cl@@e\empty \else
        \doregisterspotcolorname{#5}\@@cl@@e
      \fi}
     {\doifelsenothing\currentpalet
         \donefalse
        {\doifdefinedelse{\??cr\currentpalet#6}\donetrue\donefalse}%
      \ifdone
        \doifnot{#5}{#6}
           {#2{\??cr#5}{\paletcolorspec{#6}}}%
      \else
        \doifdefinedelse{\??cr#6}
           {\doifelse{#5}{#6}
              {% this way we can freeze \definecolor[somecolor][somecolor]
               % and still prevent cyclic definitions
               \iffreezecolors#3{\??cr#5}{\csname\??cr#6\endcsname}\fi}
              {\iffreezecolors\@EA#3\else\@EA#2\fi{\??cr#5}{\csname\??cr#6\endcsname}}}
           {\showmessage\m!colors3{#5 (def)}}%
       \fi}%
   \ifcase#4\or
     \unexpanded#2{#5}{\switchtocolor[#5]}% \unexpanded toegevoegd
   \fi}

\def\paletcolorspec#1%
  {\csname\??cr\currentpalet#1\endcsname}

%D Hex color support is not enabled by default. You need to say \type
%D {\setupcolor [hex]} to get this working.

\ifx\colorHpattern\undefined \let\colorHpattern\colorZpattern \fi

%D New and experimental.

\def\dodefinespotcolor[#1][#2][#3]% todo: always global
  {\doifnot{#1}{#2}
     {\@@resetcolorparameters
      \doglobal\addtocommalist{#1}\colorlist % optional
      \edef\@@cl@@n{#2}%
      \getparameters[\??cl @@][#3]%
      \doifnothing\@@cl@@p{\let\@@cl@@p\!!plusone}%
      \ifx\@@cl@@e\empty \else
        \doregisterspotcolorname{#2}\@@cl@@e
      \fi
      \doglobal\addtocommalist{#2}\allspotcolors
      \setxvalue{\??cr#1}{\colorPpattern}% was \setevalue
      \setgvalue{#1}{\switchtocolor[#1]}}} % was \setvalue

\def\registerusedspotcolors
  {\ifx\allspotcolors\empty \else
     \bgroup
     \let\usedspotcolors\empty
     \def\docommand##1%
       {\doifdefined{\??cs##1}{\addtocommalist{##1}\usedspotcolors}}%
     \processcommacommand[\allspotcolors]\docommand
     \savecurrentvalue\usedspotcolors\usedspotcolors
     \egroup
   \fi}

\def\registerusedcolorchannels
  {\bgroup
   \doifdefinedelse{\??cs c}
     {\def\usedcolorchannels{c,m,y,k}}%
     {\let\usedcolorchannels\empty}%
   \doifdefined{\??cs r}
     {\addtocommalist{r,g,b}\usedcolorchannels}%
   \doifdefined{\??cs s}
     {\ExpandBothAfter\doifnotinset{k}\usedcolorchannels
        {\addtocommalist{s}\usedcolorchannels}}%
   \savecurrentvalue\usedcolorchannels\usedcolorchannels
   \egroup}

\prependtoks
  \registerusedspotcolors
  \registerusedcolorchannels
\to \everylastshipout

\def\registerusedspotcolor#1%
  {\global\@EA\chardef\csname\??cs#1\endcsname\zerocount}

%D On top of spotcolors, we define multitone colors. You'd better know
%D what you're doing because invalid definitions will lead to invalid
%D documents (i.e.\ resources).

% \definecolor [darkblue]   [c=.5,m=.5]
% \definecolor [darkyellow] [y=.5]
%
% \definemultitonecolor [whatever] [darkblue=.5,darkyellow=.5] [c=.25,m=.25,y=.25] [a=1,t=.5]
% \definemultitonecolor [another]  [darkblue=.5,darkyellow=.5] [c=.25,m=.25,y=.25]

\def\dodefinemultitonecolor[#1][#2][#3][#4]%
  {\let\@@cl@@cl@@D\empty % n's
   \let\@@cl@@cl@@P\empty % p's
   \let\@@cl@@cl@@N\empty % name
   \scratchcounter\zerocount
   \processcommacommand[#2]\dododefinemultitonecolor
   \bgroup
     \lccode`\.=`\_%
     \lccode`\,=`\_%
     \lccode`\:=`\_%
     \lccode`\;=`\_%
     \lccode`\+=`\_%
     \lccode`\-=`\_%
     \lccode`\*=`\_%
     \lccode`\/=`\_%
%      \lccode`\_=`\_%
     % not needed, other attribute in driver:
     %
     % \@@resetcolorparameters
     % \getparameters[#4]%
     % \ifx\@@cl@@t\@@cl@@z\else
     %   \edef\@@cl@@cl@@N{\@@cl@@cl@@N_\@@cl@@t_\@@cl@@a}%
     % \fi
     \lowercase\@EA{\@EA\xdef\@EA\@@cleancolor\@EA{\@@cl@@cl@@N}}%
   \egroup
   \setxvalue{\??cl\@@cleancolor\s!check}{\noexpand\docheckmultitonecolor{\@@cl@@cl@@D}}%
   \expanded{\defineglobalcolor[\@@cleancolor][#3,#4]}%
   \expanded{\definespotcolor[#1][\@@cleancolor][#4,f=\the\scratchcounter,p={\@@cl@@cl@@P},d={\@@cl@@cl@@D}]}}

\def\docheckmultitonecolor#1%
  {\flushatshipout
     {\let\checkmultitonecolor\gobbleoneargument
      \def\docommand##1{\hbox{\definecolor[\s!dummy-100][##1][p=1]\color[\s!dummy-100]}}%
      \processcommalist[#1]\docommand}}

\def\checkmultitonecolor#1%
  {\csname\??cl#1\s!check\endcsname\letgvalue{\??cl#1\s!check}\relax}

\def\dodefinespotcolor[#1][#2][#3]% todo: always global (REDEFINED)
  {\doifnot{#1}{#2}
     {\@@resetcolorparameters
      \doglobal\addtocommalist{#1}\colorlist % optional
      \edef\@@cl@@n{#2}%
      \getparameters[\??cl @@][#3]%
      \doifnothing  \@@cl@@p{\let\@@cl@@p\!!plusone}%
      \doifsomething\@@cl@@e{\doregisterspotcolorname{#2}\@@cl@@e}%
      \doglobal\addtocommalist{#2}\allspotcolors
      \setxvalue{\??cr#1}{\colorPpattern}% was \setevalue
      \setgvalue{#1}{\switchtocolor[#1]}}}% was \setvalue

\def\dododefinemultitonecolor#1%
  {\advance\scratchcounter\plusone
   \splitstring#1\at=\to\!!stringa\and\!!stringb
   \ifx\@@cl@@cl@@D\empty
     \let\@@cl@@cl@@D\!!stringa
     \let\@@cl@@cl@@P\!!stringb
     \normalizecolor\!!stringb
     \edef\@@cl@@cl@@N{\!!stringa_\!!stringb}%
   \else
     \edef\@@cl@@cl@@D{\@@cl@@cl@@D,\!!stringa}%
     \edef\@@cl@@cl@@P{\@@cl@@cl@@P,\!!stringb}%
     \normalizecolor\!!stringb
     \edef\@@cl@@cl@@N{\@@cl@@cl@@N_\!!stringa_\!!stringb}%
   \fi}

% \def\dododefinemultitonecolor#1% a/b safe
%   {\advance\scratchcounter\plusone
%    \splitstring#1\at=\to\@@cl@@one\and\@@cl@@two
%    \ifx\@@cl@@cl@@D\empty
%      \let\@@cl@@cl@@D\@@cl@@one
%      \let\@@cl@@cl@@P\@@cl@@two
%      \normalizecolor\@@cl@@two
%      \edef\@@cl@@cl@@N{\@@cl@@one_\@@cl@@two}%
%    \else
%      \edef\@@cl@@cl@@D{\@@cl@@cl@@D,\@@cl@@one}%
%      \edef\@@cl@@cl@@P{\@@cl@@cl@@P,\@@cl@@two}%
%      \normalizecolor\@@cl@@two
%      \edef\@@cl@@cl@@N{\@@cl@@cl@@N_\@@cl@@one_\@@cl@@two}%
%    \fi}

%D The names of colors are stored in a comma separated list
%D only for the purpose of showing them with \type {\showcolor}.
%D
%D \startbuffer
%D \definecolor [SomeKindOfRed] [r=.8,g=.05,b=.05]
%D \stopbuffer
%D
%D \typebuffer
%D \getbuffer
%D
%D This color shows up as \color [SomeKindOfRed] {some kind
%D of red}.
%D
%D \starttyping
%D \setupcolors[state=start]
%D
%D \definecolor[mygreen][green]
%D \definecolor[green][g=.5]
%D
%D \startcolor[mygreen]test\stopcolor
%D
%D \setupcolors[expansion=no]
%D
%D \definecolor[mygreen][green]
%D \definecolor[green][g=.5]
%D
%D \startcolor[mygreen]test\stopcolor
%D \stoptyping

%D \macros
%D   {startcolormode,stopcolormode,permitcolormode}
%D
%D We use \type{\stopcolormode} to reset the color in
%D whatever color space and do so by calling the corresponding
%D special. Both commands can be used for fast color
%D switching, like in colored verbatim,

\newif\ifpermitcolormode \permitcolormodetrue

\def\dowithcolor#1#2% #1=\action #2=color
  {\ifincolor\ifpermitcolormode
     \ifcsname\??cr\currentpalet#2\endcsname
       \handlecolorwith#1\csname\??cr\currentpalet#2\endcsname\od
     \else\ifcsname\??cr#2\endcsname
       \handlecolorwith#1\csname\??cr#2\endcsname\od
     \fi\fi
   \fi\fi}

\def\startcolormode % includes \ifincolor\ifpermitcolormode
  {%\dostoptransparency % needed for: {test \trans test \notrans test}
   \conditionalstoptransparency
   \dowithcolor\execcolorRCSP}

\def\stopcolormode
  {\ifincolor\ifpermitcolormode
     \supportedstoptransparency
     \dostopcolormode
   \fi\fi}

\def\restorecolormode
  {\ifincolor\ifpermitcolormode
     \supportedstoptransparency
     \dostopcolormode
     \ifx\maintextcolor\empty \else
       \startcolormode\maintextcolor
     \fi
   \fi\fi}

%D Color modes are entered using the next set of commands.
%D The \type{\stop} alternatives are implemented in a way
%D that permits non||grouped use.
%D
%D The, for this module redundant, check if we are in color
%D mode is needed when we use these macros in other modules.

\def\execcolorRCSP#1:%
  {\csname execcolor#1\endcsname}

\def\execcolorR
  {\iffilterspotcolor
     \@EA\noexeccolorR
   \else
     \@EA\doexeccolorR
   \fi}

\def\execcolorC
  {\iffilterspotcolor
     \@EA\noexeccolorC
   \else
     \@EA\doexeccolorC
   \fi}

\def\execcolorS
  {\iffilterspotcolor
     \@EA\noexeccolorS
   \else
     \@EA\doexeccolorS
   \fi}

\def\execcolorP
  {\iffilterspotcolor
     \@EA\doexeccolorPP
   \else\ifcase\currentcolorchannel
     \@EAEAEA\doexeccolorP
   \else
     \@EAEAEA\noexeccolorP
   \fi\fi}

\def\doexeccolorR#1:#2:#3:%
  {\edef\@@cl@@r{#1}\edef\@@cl@@g{#2}\edef\@@cl@@b{#3}%
   \ifpreferGRAY\ifx\@@cl@@r\@@cr@@g\ifx\@@cl@@r\@@cl@@b
     \GRAYpreferedtrue
   \fi\fi\fi
   \ifincolor\else\RGBsupportedfalse\CMYKsupportedfalse\fi
   \ifGRAYprefered
     \registercolorchannel\c!s
     \let\@@cl@@s\@@cl@@r
     \normalizeGRAY
     \doexeccolorgray
   \else\ifRGBsupported
     \registercolorchannel\c!r
     \normalizeRGB
     \doexeccolorrgb
   \else\ifCMYKsupported
     \registercolorchannel\c!c
     \convertRGBtoCMYK\@@cl@@r\@@cl@@g\@@cl@@b
     \normalizeCMYK
     \doexeccolorcmyk
   \else
     \registercolorchannel\c!s
     \convertRGBtoGRAY\@@cl@@r\@@cl@@g\@@cl@@b
     \normalizeGRAY
     \doexeccolorgray
   \fi\fi\fi
   \exectransparency}

\def\doexeccolorC#1:#2:#3:#4:%
  {\edef\@@cl@@c{#1}\edef\@@cl@@m{#2}\edef\@@cl@@y{#3}\edef\@@cl@@k{#4}%
   \ifpreferGRAY\ifx\@@cl@@k\@@cl@@z\ifx\@@cl@@c\@@cr@@m\ifx\@@cl@@c\@@cl@@y
     \GRAYpreferedtrue
   \fi\fi\fi\fi
   \ifincolor\else\RGBsupportedfalse\CMYKsupportedfalse\fi
   \ifGRAYprefered
     \registercolorchannel\c!s
     \let\@@cl@@s\@@cl@@c
     \normalizeGRAY
     \doexeccolorgray
   \else\ifCMYKsupported
     \registercolorchannel\c!c
     \ifreduceCMYK
       \convertCMYKtoCMY\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
     \fi
     \normalizeCMYK
     \doexeccolorcmyk
   \else\ifRGBsupported
     \registercolorchannel\c!r
     \convertCMYKtoRGB\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
     \normalizeRGB
     \doexeccolorrgb
   \else
     \registercolorchannel\c!s
     \convertCMYKtoGRAY\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
     \normalizeGRAY
     \doexeccolorgray
   \fi\fi\fi
   \exectransparency}

\def\doexeccolorS#1:%
  {\edef\@@cl@@s{#1}%
   \registercolorchannel\c!s
   \normalizeGRAY
   \doexeccolorgray
   \exectransparency}

% \def\doexeccolorP#1:#2:%
%   {\edef\@@cl@@n{#1}%
%    \edef\@@cl@@p{#2}%
%    \registerusedspotcolor\@@cl@@n
%    \ifSPOTsupported
%      \dowithcolor\registerspotcolor\@@cl@@n
%      \dostartspotcolormode\@@cl@@n\@@cl@@p
%    \else
%      \doingspotcolortrue
%      \let\spotcolorfactor\@@cl@@p
%      \factorizecolortrue            % using counter and array
%      \dowithcolor\execcolorRCSP\@@cl@@n
%      \factorizecolorfalse
%      \let\spotcolorfactor\@@cl@@o
%      \doingspotcolorfalse
%    \fi
%    \exectransparency}

\def\doexeccolorP#1:#2:#3:#4:%
  {\edef\@@cl@@n{#1}% name
   \edef\@@cl@@f{#2}% fractions
   \edef\@@cl@@d{#3}% definitions
   \edef\@@cl@@p{#4}%
   \ifx\@@cl@@d\empty
     \let\@@cl@@d\@@cl@@n
   \fi
   \registerusedspotcolor\@@cl@@n
   \ifSPOTsupported
     \checkmultitonecolor\@@cl@@n
     \dowithcolor\registerspotcolor\@@cl@@n
     \dostartspotcolormode\@@cl@@n\@@cl@@p
   \else
     \doingspotcolortrue
     \normalizespotcolor\@@cl@@p
     \let\spotcolorfactor\@@cl@@p
     \factorizecolortrue            % using counter and array
     \dowithcolor\execcolorRCSP\@@cl@@n
     \factorizecolorfalse
     \let\spotcolorfactor\@@cl@@o
     \doingspotcolorfalse
   \fi
   \exectransparency}

\def\doexeccolorPindex#1:#2:#3:#4:%
  {\edef\@@cl@@n{#1}%
   \edef\@@cl@@f{#2}%
   \edef\@@cl@@d{#3}%
   \edef\@@cl@@p{#4}%
   \ifx\@@cl@@d\empty
     \let\@@cl@@d\@@cl@@n
   \fi
   \ifSPOTsupported
     \checkmultitonecolor\@@cl@@n
     \dowithcolor\registerindexcolor\@@cl@@n
   \fi
   \noexectransparency}

\def\doexeccolorPP#1:#2:%
  {\edef\@@cl@@n{#1}%
   \edef\@@cl@@p{#2}%
   \registerusedspotcolor\@@cl@@n
   \ifx\@@cl@@n\currentspotcolor
     \normalizeSPOT
     \dostartgraycolormode\@@cl@@p % was spotcolormode
   \else
     \dovidecolor\@@cl@@p\@@cl@@o
   \fi
   \exectransparency}

\def\doexeccolorrgb
  {\ifcase\currentcolorchannel
     \dostartrgbcolormode\@@cl@@r\@@cl@@g\@@cl@@b
   \or \or \or \or
   \or \dostartgraycolormode\@@cl@@r
   \or \dostartgraycolormode\@@cl@@g
   \or \dostartgraycolormode\@@cl@@b
   \fi}

\def\doexeccolorcmyk
  {\ifcase\currentcolorchannel
       \dostartcmykcolormode\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
   \or \negatecolorcomponent\@@cl@@c\dostartgraycolormode\@@cl@@c
   \or \negatecolorcomponent\@@cl@@m\dostartgraycolormode\@@cl@@m
   \or \negatecolorcomponent\@@cl@@y\dostartgraycolormode\@@cl@@y
   \or \negatecolorcomponent\@@cl@@k\dostartgraycolormode\@@cl@@k
   \fi}

\def\doexeccolorgray
  {\ifcase\currentcolorchannel
       \dostartgraycolormode\@@cl@@s
   \or \or \or
   \or \dostartgraycolormode\@@cl@@s
   \or \or \or
   \or \dostartgraycolormode\@@cl@@s
   \fi}

%D When filtering colors, we need to either erase
%D the background, or ignore the foreground.

% \newif\ifhidesplitcolor \hidesplitcolortrue
%
% \def\noexeccolor#1\od
%   {\dostartgraycolormode\@@cl@@o}
%
% \let\noexeccolorS\noexeccolor
% \let\noexeccolorP\noexeccolor

%D Well, here comes some real trickery. When we have the 100\%
%D spot color or black color, we don't want to erase the
%D background. So, instead we hide the content by giving it
%D zero transparency.

% todo : #1#2#3 met #2 > of < and #3 een threshold

\def\dohidecolor#1#2%
  {\ifhidesplitcolor
     \ifx#1#2%
       \dostartgraycolormode\@@cl@@o
     \else
       \doregisternonecolor
       \dostartnonecolormode
     \fi
   \else
     \dostartgraycolormode\@@cl@@o
   \fi}

\def\dovidecolor#1#2%
  {\ifhidesplitcolor
     \ifx#1#2%
       \doregisternonecolor
       \dostartnonecolormode
     \else
       \dostartgraycolormode\@@cl@@o
     \fi
   \else
     \dostartgraycolormode\@@cl@@o
   \fi}

% \def\fullytransparentcolor % fails on floats
%   {\dostartgraycolormode\@@cl@@o % better than z
%   %\global\@EA\chardef\csname\@@currenttransparent\endcsname\plusone
%   %\global\intransparenttrue
%    \dostarttransparency10}

\def\noexeccolorR#1:#2:#3:#4\od
  {\edef\@@cl@@r{#1}\edef\@@cl@@g{#2}\edef\@@cl@@b{#3}%
   \dohidecolor\@@cl@@s\@@cl@@o}

\def\noexeccolorC#1:#2:#3:#4:#5\od
  {\edef\@@cl@@c{#1}\edef\@@cl@@m{#2}\edef\@@cl@@y{#3}\edef\@@cl@@k{#4}%
   \dohidecolor\@@cl@@s\@@cl@@o}

\def\noexeccolorS#1:#2\od
  {\edef\@@cl@@s{#1}%
   \dohidecolor\@@cl@@s\@@cl@@o}

\def\noexeccolorP#1:#2:#3:#4:#5\od
  {\edef\@@cl@@p{#4}%
   \dohidecolor\@@cl@@p\@@cl@@z}

%D For the sake of postprocessing (i.e.\ color separation)
%D we can normalize colors, which comes down to giving equal
%D values an equal accuracy and format. This feature is
%D turned off by default due to a speed penalty. This macro
%D also handles spot color percentages.

\newif\iffactorizecolor
\newif\ifnormalizecolor

\def\spotcolorfactor{1}

% \def\normalizecolor#1%
%   {\colordimen#1\thousandpoint
%    \colordimen\spotcolorfactor\colordimen
%    \colorcount\colordimen
%    \advance\colorcount \medcard
%    \divide\colorcount \maxcard
%    \edef#1{\realcolorvalue\colorcount}}

\def\normalizecolor#1%
  {\colorcount\numexpr(\dimexpr\spotcolorfactor\dimexpr#1\thousandpoint\relax\relax+\medcard)/\maxcard\relax
   \edef#1{\realcolorvalue\colorcount}}

% \def\normalizespotcolor#1%
%   {\colordimen-#1\thousandpoint
%    \advance\colordimen\thousandpoint
%    \colorcount\colordimen
%    \advance\colorcount \medcard
%    \divide\colorcount \maxcard
%    \edef#1{\realcolorvalue\colorcount}}

\def\normalizespotcolor#1%
  {\colorcount\numexpr(\dimexpr\thousandpoint-#1\thousandpoint\relax+\medcard)/\maxcard\relax
   \edef#1{\realcolorvalue\colorcount}}

\def\donormalizeRGB
  {\normalizecolor\@@cl@@r
   \normalizecolor\@@cl@@g
   \normalizecolor\@@cl@@b}

\def\normalizeRGB
  {\ifnormalizecolor
     \donormalizeRGB
   \else\iffactorizecolor
     \donormalizeRGB
   \fi\fi}

\def\donormalizeCMYK
  {\normalizecolor\@@cl@@c
   \normalizecolor\@@cl@@m
   \normalizecolor\@@cl@@y
   \normalizecolor\@@cl@@k}

\def\normalizeCMYK
  {\ifnormalizecolor
     \donormalizeCMYK
   \else\iffactorizecolor
     \donormalizeCMYK
   \fi\fi}

\def\donormalizeGRAY
  {\normalizecolor\@@cl@@s}

\def\normalizeGRAY
  {\ifnormalizecolor
     \donormalizeGRAY
   \else\iffactorizecolor
     \donormalizeGRAY
   \fi\fi}

\def\normalizeSPOT
  {\normalizespotcolor\@@cl@@p}

%D We need to register spot colors (i.e.\ resources need to
%D be created.

\def\registerspotcolor#1:%
  {\ifcsname\??cl:\c!p:\@@cl@@n\endcsname
     \@EA\dontregisterspotcolor
   \else
     \letgvalue{\??cl:\c!p:\@@cl@@n}\empty
     %\@EA\@EA\csname registerspotcolor#1\endcsname
     \csname registerspotcolor#1\@EA\endcsname
   \fi}

% todo: convert to rgb if needed, will will do this in mkiv

\def\dontregisterspotcolor         #1\od{}
\def\registerspotcolorR   #1:#2:#3:#4\od{\doregisterrgbspotcolor \@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}{#2}{#3}}
\def\registerspotcolorC#1:#2:#3:#4:#5\od{\doregistercmykspotcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}{#2}{#3}{#4}}
\def\registerspotcolorS         #1:#2\od{\doregistergrayspotcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{<