最近我对纯 TeX 产生了兴趣,因为它比常规 LaTeX 具有更大的灵活性。
在我的文档中,我希望使用文本的灰度。在 LaTeX 中,通过包可以产生此结果color
。David Carlisletexdoc color
提供了有关该包的出色文档graphics
,但缺少有关实现的大量文档。
或者,我可以尝试以自己的方式来解决xcolor
,虽然在实施方面会复杂得多,但请注意,该包中也缺少有关实施的完整章节。
我在论坛上找到了一些解决方法comp.text.tex
(http://compgroups.net/comp.text.tex/problem-using-color-and-graphicx-in-plain-tex/1918061),这当然非常简单的并且(如果你愿意)方便的但这些解决方案本质上与使用纯 TeX 的原因,即纯 TeX 格式不受时间流逝的影响。在纯 TeX 文档中使用 LaTeX 包可能会被认为触及灰色区域,例如“该包不太可能在不久的将来发生变化”。但是,从我的角度来看,这个问题的目的可以延伸得更远,给出图形驱动程序(我假设它在包和相关包中发挥作用)和 TeXcolor
之间互锁的实现概述。color
所以我想询问一下该color
包在纯 TeX 中的实现,或者具有类似功能的替代实现。
答案1
由于问题集中在学习如何使用原语来完成这些事情(我同意大卫的回答以普通方式加载color
包裹是更简单的方法)。
我在这里要做的是实现与该color
包所采用的方法大致相同的方法,并对经典 TeX(dvips
或dvipdfm(x)
驱动程序)、PDF 模式下的 pdfTeX/LuaTeX 和 XeTeX 进行适当的测试。由于还有一些事情要做,我将在代码中穿插一些注释。
首先,设置一个条件来测试直接 PDF 输出
\newif\ifpdfmode
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname pdfoutput\endcsname\relax
\else
\ifnum\pdfoutput>0 %
\expandafter\expandafter\expandafter\pdfmodetrue
\fi
\fi
将当前颜色定义为黑色,使用以便\edef
一旦定义就没有条件(同样的想法适用于其余代码)
\edef\currentcolor{%
\ifpdfmode
0 g 0 G%
\else
gray 0%
\fi
}
设置预定义颜色:我刚刚做了一个(红色)作为演示:
\edef\colorred{%
\ifpdfmode
1 0 0 rg 1 0 0 RG%
\else
rgb 1 0 0%
\fi
}
对于直接 PDF 输出,可能有一个可用的颜色堆栈(自 pdfTeX 1.40.0 起)。一次性测试会告诉我们这一点:如果没有堆栈,只需手动恢复颜色。有关详细信息,请参阅此处的 pdfTeX 手册。
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname pdfcolorstack\endcsname\relax
\ifpdfmode
\def\pdfcolorstackpush{\pdfliteral{\currentcolor}}%
\let\pdfcolorstackpop\pdfcolorstackpush
\fi
\else
\chardef\colorstack=0 %
\def\pdfcolorstackpush{%
\pdfcolorstack\colorstackcnt push{\currentcolor}%
}%
\def\pdfcolorstackpop{%
\pdfcolorstack\colorstackcnt pop\relax%
}%
\fi
设置颜色的主要宏从测试开始:如果参数是预定义颜色的名称,则使用该名称,否则假设为硬编码的引擎特定值。(更复杂的方法是将颜色转换为正确的格式:因为问题中没有要求这样做,所以我将其留作练习)。设置颜色后,插入适当的特殊(注意,\edef
将再次意味着在使用时没有条件):
\edef\color#1{%
\begingroup\noexpand\expandafter\noexpand\expandafter\noexpand\expandafter\endgroup
\noexpand\expandafter\noexpand\ifx\noexpand\csname color#1\noexpand\endcsname\relax
\def\noexpand\currentcolor{#1}%
\noexpand\else
\noexpand\expandafter\let\noexpand\expandafter\noexpand\currentcolor
\noexpand\csname color#1\noexpand\endcsname
\noexpand\fi
\ifpdfmode
\noexpand\pdfcolorstackpush
\else
\special{color push \noexpand\currentcolor}%
\fi
\aftergroup\noexpand\resetcolor
}
按照该color
方法,还使用适当的特殊方法创建重置宏。
\edef\resetcolor{%
\ifpdfmode
\noexpand\pdfcolorstackpop
\else
\special{color pop}%
\fi
}
演示本身。上面的实现依赖于框内的分组级别,在 LaTeX 中,这将由\savebox
“包装器”完成\hbox
(等等)。实际上情况并非如此,因此颜色安全框需要一个组。当然,这可以放在一组适当的包装器宏中:
\newbox\mybox
\setbox\mybox=\hbox{\begingroup\color{red}Red text\endgroup}
Surrounding text \box\mybox \space and more of it.
\bye
(注意:我构建上述内容的方式与使用 DocStrip 创建单独文件的方式非常相似。由于不涉及 DocStrip,因此这需要一些条件/edef
工作。)
答案2
乳胶graphics
和color
包装可以以普通纤维形式使用。http://www.ctan.org/pkg/miniltx
的维护者texdoc
选择展示grfguide.pdf
如果texdoc color
您去texdoc color.pdf
那么您将获得彩色包文档,其中包括完整索引的源列表。
plain tex 具有一些优点,它是一种简单的格式,可用于教授如何构建格式,但我真的无法想象它比 latex 更灵活。LaTeX 不会删除任何功能。
答案3
我在 OPmac 软件包中为 plainTeX 实现了全彩色功能。所以我知道问题出在哪里。
\pdfliteral
您可以使用或简单地将颜色选择器放入排版材料中\special
,但您必须记住,从 TeX 的角度来看,颜色从这一点到页面末尾的变化与分组/段落等无关。例如,\pdfliteral{1 0 0 r}
意味着从这一点到页面末尾的所有文本(包括脚注、页码等)都是红色,下一页重新初始化为黑色。如果您在框中打印某些内容,而这些内容不能分成更多页面,那么
\hbox{\pdfliteral{1 0 0 r}Something in red\pdfliteral{0 g}}
就足够了。但如果颜色可以分成更多页面,或者您需要颜色堆栈(即可以返回到以前的颜色 - 没有明确的黑色),那么您必须更正标题/脚注,\plainoutput
并且必须在页面上实现颜色管理系统,管理颜色堆栈等。此外,PDF 中有两种类型的颜色选择器:用于描边和用于填充。您可以独立管理它们,也可以在任何地方将两者设置为相同的颜色。
我已经在 OPmac 的技术文档中从实施的角度描述了所有这些功能:opmac-d.pdf
,但抱歉,它只有捷克语。
答案4
我尝试重写 Joseph Wright 编写的宏,使其更易读。他的宏不太易读,因为 1) 在测试原语是否存在时存在多余的 expandafters、begingroups、csnames 等;2)\edef
对宏的两个变体使用了 ,而不是仅使用\ifpdfmode
一次 。
该评论与约瑟夫的回答相同。
\newif\ifpdfmode
\ifx\pdfoutput\undefined
\else
\ifnum\pdfoutput>0 \pdfmodetrue
\fi
\fi
\ifpdfmode
\def\colorblack {0 g 0 G}
\def\colorred {1 0 0 rg 1 0 0 RG}
\def\colorgreen {0 1 0 rg 0 1 0 RG}
\def\colorblue {0 0 1 rg 0 0 1 RG}
\ifx\pdfcolorstack\undefined
\def\pdfcolorstackpush{\pdfliteral{\currentcolor}}
\let\pdfcolorstackpop\pdfcolorstackpush
\else
\mathchardef\colorstackcnt=\pdfcolorstackinit page {\colorblack}
\def\pdfcolorstackpush{\pdfcolorstack\colorstackcnt push{\currentcolor}}
\def\pdfcolorstackpop{\pdfcolorstack\colorstackcnt pop}
\fi
\else % of \ifpdfmode
\def\colorblack {gray 0}
\def\colorred {rgb 1 0 0}
\def\colorgreen {rgb 0 1 0}
\def\colorblue {rgb 0 0 1}
\def\pdfcolorstackpush{\special{color push \currentcolor}}
\def\pdfcolorstackpop{\special{color pop}}
\fi % of \ifpdfmode
\def\color#1{\expandafter
\ifx\csname color#1\endcsname \relax \def\currentcolor{#1}%
\else \edef\currentcolor{\csname color#1\endcsname}%
\fi
\pdfcolorstackpush
\aftergroup\pdfcolorstackpop
}
\let\currentcolor=\colorblack
如果颜色扩展到更多页,我们需要将页码设置为黑色:
\footline={\color{black}\hss\tenrm\folio\hss}
测试如下:
Surrounding text {\color{red}Red text} and more of it.
Text {\color{blue}text
{\color{green}gree gr ee g re eg re
\vfil\break
egrg ree g reeg ree greeg grr reeg ree gre eee
green text} textik} end.
\bye
编辑我关于将页码设为黑色的第一个建议只是对新问题的简单介绍。现在,我们可以\footline=...
从代码中删除该行,这样我们就可以更概念化地处理问题。
我们需要重新定义,\plainoutput
以便\headline
,\footline
\topins
和\footins
在每一页都用黑色初始化。为此,我们在输出例程中本地设置\currentcolor
为\colorblack
,并且我们需要用 ,对包围,\makeheadline
和。这意味着以下重新定义:\makefooline
\unvbox\topins
\footnoterule\unvbox\footins
\pdfcolorstackpush
\pdfcolorstackpop
\def\plainoutput{%
\let\currentcolor=\colorblack
\shipout\vbox{\pdfcolorstackpush\makeheadline\pdfcolorstackpop
\pagebody
\pdfcolorstackpush\makefootline\pdfcolorstackpop}%
\advancepageno
\ifnum\outputpenalty>-20000 \else\dosupereject\fi
}
\def\pagecontents{%
\ifvoid\topins\else\pdfcolorstackpush\unvbox\topins\pdfcolorstackpop\fi
\dimen0=\dp255 \unvbox255
\ifvoid\footins\else
\vskip\skip\footins
\pdfcolorstackpush\footnoterule
\unvbox\footins\pdfcolorstackpop\fi
\csname ifr@ggedbottom\endcsname \kern-\dimen0 \vfil \fi
}
笔记颜色堆栈与 TeX 分组机制的同步是通过 实现的\aftergroup
,这有时很脆弱。Joseph 提到问题在于,\setbox=\hbox{...\aftergroup\token...}
因为\aftergroup
标记是在设置框后处理的,因此\pdfcolorstackpop
插入到使用的材料中\setbox
,而不是在 内\hbox
。因此我们需要编写
\setbox0=\hbox{{\color{red}text}}
第二个例子,它很脆弱,\footnote*{\color{green}text}
但你可以重新定义\footnote
,让用户更舒服。
笔记2PDFTeX 提供多个堆栈,PDF 规范提供了两种类型的颜色选择器:1 0 0 r
用于填充和1 0 0 R
用于描边。上面的示例并行使用了两个选择器(如color.sty
),但我们可以为第二个颜色选择器初始化第二个独立的颜色堆栈,并让用户可以选择正确的颜色选择器(用于文本或线条),就像 OPmac 所做的那样。但问题就在这里:xdvipdfmx
使用 时没有更多独立的颜色堆栈。并且在宏级别实现两个独立的颜色堆栈稍微复杂一些(OPmac 这样做是因为它的宏比\pdfcolorstack
原始宏更旧)。