我怎样才能改变文本颜色以使其效果超越群组?

我怎样才能改变文本颜色以使其效果超越群组?

我希望有一个命令\globalred,使所有后续文本变为红色,即使该命令是在组内发出的。例如,TeX 文件的输出

\documentclass{article}
\begin{document}
a {\globalred b} c
\end{document}

应该是  期望输出,用红色的c。我确实有一些非常棘手的解决方案,但它只能通过重新定义\set@color\reset@color命令来工作,从pdftex.def到它们所在的位置版本 0.03t(或者使用 2007 年之前的旧 TeX 安装):

\documentclass{article}
\usepackage[pdftex]{xcolor}
\makeatletter
\def\set@color  {\pdfliteral{\current@color}%
                 \aftergroup\reset@color}
\def\reset@color{\pdfliteral{\current@color}}
\def\globalred  {\xdef\current@color{\xcolor@ {}{1 0 0 rg 1 0 0 RG}{rgb}{1,0,0}}%
                 \set@color}
\makeatother
\begin{document}
a {\globalred b} c
\end{document}

这让我想到以下问题:

  • 有没有“官方”的方法来实现我的目标?
  • 为什么\set@color从较新的pdftex.def版本开始不再具有全局作用,尽管我\current@color用进行了全局重新定义\xdef?(这是设计选择还是新实现的不可预见的副作用\set@color?)

让我简单解释一下我是如何想到这个的:在上面我的代码中,我粗略地模拟了beamer生成透明文本的操作。beamer旨在以一种超越群体的方式来做到这一点(参见用户指南,第 24 页和第 79 页),但它似乎不再起作用了;至少对我来说,第 79 页上的示例给出了奇怪的输出:

带有停顿的 itemize 奇怪输出

同样的问题(和黑客解决方案)出现在这个问题是我的

答案1

在 LaTeX 中没有官方的方法来实现这一点。颜色变化与组绑定。“全局技巧”之所以适用于旧版本,pdftex.def是因为那里的颜色实现存在缺陷。旧版本的 pdfTeX 不提供颜色堆栈,因此在分页方面存在严重问题。

Dvips 提供了一个颜色堆栈,其中当前颜色放在驱动程序的堆栈上,颜色更改后,堆栈的颜色会恢复,而\current@color不会在恢复颜色值时使用。pdftex.def如果和 pdfTeX 不是太旧的话,现在也会发生同样的情况。此外,pdfTeX 通过支持多个颜色堆栈改进了 dvips 的颜色堆栈。例如,可以为脚注(包pdfcol)使用额外的颜色堆栈来支持跨页脚注的颜色更改。有关其他示例,请参阅包pdfcolparrallelpdfcolparcolumns。此外,可以通过这种方式管理颜色以外的其他参数,请参阅pdftransparent透明度或的示例包pdfrender

\documentclass{article}
\usepackage[pdftex]{xcolor}
\makeatletter
\def\set@color{%
  \pdfliteral{\current@color}%
  \aftergroup\reset@color
}
\def\reset@color{%
  \pdfliteral{\current@color}%
}
% colorfix stuff for old implementation of color for pdfTeX
\RequirePackage{ltxcmds}
\AtBeginDocument{%
  \ltx@ifundefined{@ldc@l@r}{%
    \let\@ldc@l@r\color
    \def\color{%
      \ltx@IfUndefined{if@inlabel}{}{%
        \csname if@inlabel\expandafter\endcsname
        \expandafter\leavevmode\csname fi\endcsname
      }%
      \@ldc@l@r
    }%
  }{}%
  \ltx@ifundefined{@lduseb@x}{%
    \ltx@IfUndefined{usebox}{}{%
      \let\@lduseb@x\usebox
      \def\usebox#1{\@lduseb@x{#1}\reset@color}%
    }%
  }{}%
}

\newcommand*{\globalcolor}{%
  \let\saved@set@color\set@color
  \def\set@color{%
    \saved@set@color
    \global\let\current@color\current@color
    \let\set@color\saved@set@color
  }%
  \color
}
\makeatother

\begin{document}
a \textcolor{blue}{b \globalcolor{red}c }d
\end{document}

例子

\pdfcolorstack可以禁用,然后pdftex.def会自动切换到旧行为。但是,这也会破坏与颜色无关的其他内容(例如pdfrender,,pdftransparent...)。

而这\globalcolor对其他驱动程序不起作用dvips。因此我不推荐这种方法。

答案2

好的,我想出了另一个不起作用的解决方案禁用pdf 颜色堆栈,但操纵它。这个想法是使用set原始选项\pdfcolorstack。我希望这比问题中的粗略想法有更少的副作用。(一个缺点是,我对的重新定义会\reset@color导致分页符出现问题;请参阅 Heiko Oberdieck 的评论。)

编辑:现在解决方案适用于pdflatexlatex -> dvips。我对驱动程序的代码不太满意dvips,但看起来如果color pop用于空颜色堆栈,驱动程序不会抱怨。

输出 c、d 和 f 为红色

\documentclass{article}
\usepackage{xcolor}
\makeatletter
\let\rs@c\reset@color
\def\dvips@driver{dvips.def}
\def\pdftex@driver{pdftex.def}
\ifx\Gin@driver\pdftex@driver
  \def\reset@color{%
    \rs@c
    \pdfcolorstack\@pdfcolorstack set{\current@color}%
  }
\fi
\ifx\Gin@driver\dvips@driver
  \def\reset@color{%
    \rs@c
    \rs@c
    \set@color
  }
\fi
\newcommand*{\globalcolor}{%
  \let\saved@set@color\set@color
  \def\set@color{%
    \saved@set@color
    \let\set@color\saved@set@color
    \global\let\current@color\current@color
  }%
  \color
}
\makeatother
\begin{document}
\textcolor{green}{%
  a \textcolor{blue}{b \globalcolor{red} c }d \textcolor{black} e
}f
\end{document}

相关内容