xcolor 的 \color 如何工作?

xcolor 的 \color 如何工作?

\color出于好奇,我查找了xcolor图书馆。我发现了这个:

\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@}}}

看起来最相关的主要内容是最后一行:

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

看起来这只是对另一种颜色的另一个函数调用。


阅读更多文档后我认为\color其定义如下:

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

然后它变得复杂了,有两个内部函数如果下一个字符是[它做一件事,否则它做另一件事:

\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}}

另一个函数用于声明颜色:

\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}

我只是想了解如何{\color{blue!50!white} this is blue!}手动编写类似的东西

答案1

这个问题大致可以从以下几个方面来理解:

  • TeX 中颜色的低级实现方式
  • 软件包宏如何color将用户级颜色指令转换为低级颜色命令
  • 该包如何xcolor扩展color以提供“混合”和相关效果

我将分别讨论这些领域。这个问题问我们关于用户级构造

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

因此我将使用这个或简化版本

{\color{blue} this is blue!}

在答案中。


在低层次上,TeX 本身根本不支持颜色。相反,它把它留给了驱动程序,通过驱动程序所需的原始格式\special和特殊格式。在现代 TeX 设置中,我们往往担心的驱动程序是直接 PDF 生成 (pdfTeX/LuaTeX)、dvips来自 pdfTeX 的 PostScript 路由以及(x)dvipdfmx来自 pdfTeX 的 XeTeX 和 DVI-to-PDF 路由。

每个驱动程序都有自己的指令和自己的颜色符号来跟踪。我将重点介绍使用 pdfTeX 直接制作 PDF 以寻找答案。它有一个原语\pdfcolorstack,需要颜色堆栈编号和颜色描述(灰度、RGB 或 CMKY 值)。因为我们稍后会使用 RGB,所以我将采用这种形式:

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

将使文本变成蓝色。如您所见,在直接 PDF 模式下有两种颜色可以设置:背景和前景。这不是通用的,所以其他驱动程序代码必须“手动”跟踪这些内容。还请注意,RGB 值是 100% 给出的,所以这里我们有全蓝色,但没有红色或绿色。


驱动程序代码的可变性和不太容易记住的颜色形式是大多数人依赖包color或后继包进行抽象的原因。如果我们使用\tracingall包,color我们会发现\color首先寻找一个可选的[。如中所述color手动的,可选参数是颜色模型,因此可能会有

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

指定蓝色而不预先定义它。在可选参数为不是找到后,将选择内部宏\@declaredcolor。它会查找名称为 的预定义颜色规范\\color@<argument>,因此对我们来说\\color@blue。假设找到了 ,它会使用该 (此处定义为0 0 1 rg 0 0 1 RG)并写入与之前相同的低级行。

颜色的定义和对它们采取的具体操作由各种依赖于驱动程序的文件定义,因此dvips即使它们需要不同的低级形式,相同的机制也会为 PDF 模式和经典模式下的 pdfTeX 提供正确的底层指令。


xcolor包通过允许“混合”扩展了上述功能,即组合两种或多种颜色。以我们的blue!50!white例子为例,这意味着我们最终得到了低级指令

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

0 0 1请注意,这是蓝色 ( ) 和白色 ( 1 1 1)的线性组合。使用\tracingall你会发现这里要做的事情比案例中要多得多color。但从根本上讲,必须做的是

  • 像以前一样获取两个参数(可选[<model>]和强制<color spec>
  • 假设没有<model>,将其分解<color spec>为指定的颜色和数量
  • 进行数学运算,得到所要求的线性组合
  • 编写适当的低级代码

答案2

您在顶部显示的代码是用于\colorbox设置具有背景颜色的框的内部代码,这就是它\color在内部调用的原因。除此之外,很难以这种普遍性回答您的问题。color 和 xcolor 包的全部目的是获取一致的用户输入,然后生成需要生成的任何内容以产生颜色,因此这取决于您使用的是 dvips 还是 dvipdfm 还是 pdftex 还是 xetex 或... 每种情况下都会生成不同的代码。从包texdoc color.dtx的文档来源开始并阅读colorxcolor使用相同的基本框架,但通过混合语法和更多颜色模型进行了极大的扩展。

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

\end{document}

使用 pdftex 将显示该颜色是通过

...\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

所以

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

\pdfcolorstack 0 pop

但是如果您只是使用原始嵌套的乳胶颜色将不起作用,当然该文档只能与 pdftex 一起使用,而不能与 latex+dvips 或 xetex 等一起使用。反汇编输出不是最好的方法,如果您需要完整的详细信息,color 和 xcolor 都有完整的记录来源。

相关内容