10

Recently I became intrigued by plain TeX because it gives even more flexibility than regular LaTeX.

In my document I wish to use grayscales of text. In LaTeX, producing this result is achieved through the color package. texdoc color gives great documentation on the graphics bundle by David Carlisle, but extensive documentation on the implementation is missing.

Alternatively I could try working my way through xcolor which is substantially more complex when it comes to its implementation, but behold, a complete chapter on the implementation is missing in that package too.

I've found some workarounds on the comp.text.tex forums (http://compgroups.net/comp.text.tex/problem-using-color-and-graphicx-in-plain-tex/1918061), which is of course very easy and (if you will) convenient, but these solutions conflict at its heart with the primary reason as outlined in Reasons to use plain TeX, namely that the plain TeX format is not affected by the sands of time. Using a LaTeX package in a plain TeX document could possibly be argued to touch on a gray area, e.g. "the color package is unlikely to change in the near future". However, from my vantage point, the purpose of this question could stretch even further, giving an outline of implementation of an interlocking between a graphical driver (which I assume is at play in the color package and related packages) and TeX.

So I would like to ask about the implementation of the color package in plain TeX, or an alternative implementation with similar functionality.

  • 6
    First sentence is false of course:-) – David Carlisle Oct 15 '14 at 12:41
  • The latex graphics and color packages may be used in plain tex. ctan.org/pkg/miniltx – David Carlisle Oct 15 '14 at 12:42
  • 8
    First sentence is true of course:-) – wipet Oct 15 '14 at 14:14
11

As the question is focussed on learning how these things may be done just using the primitives (I'd agree with David's answer that loading the color package in plain is an easier route).

What I'll do here is implement much the same approach as is taken by the color package, with appropriate tests for classical TeX (dvips or dvipdfm(x) drivers), pdfTeX/LuaTeX in PDF mode and XeTeX. As there is a bit going on, I'll intersperse the code with comments.

First, set up a conditional to test for direct PDF output

\newif\ifpdfmode

\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname pdfoutput\endcsname\relax
\else
  \ifnum\pdfoutput>0 %
    \expandafter\expandafter\expandafter\pdfmodetrue
  \fi
\fi

Define the current colour as black, using an \edef so that once defined there are no conditionals about (the same idea applies to the rest of the code)

\edef\currentcolor{%
  \ifpdfmode
    0 g 0 G%
  \else
    gray 0%
  \fi
}

Set up a pre-defined colour: I've just done one (red) as a demo:

\edef\colorred{%
  \ifpdfmode
    1 0 0 rg 1 0 0 RG%
  \else
    rgb 1 0 0%
  \fi
}

For direct PDF output, there may be a colour stack available (since pdfTeX 1.40.0). A one-off test will tell us this: if there is no stack, just restore the colour manually. See the pdfTeX manual for the details here.

\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

The main macro to set colour starts with a test: if the argument is the name of a pre-defined colour use that, otherwise assume a hard-coded engine-specific value. (A more sophisticated approach is to convert the colour to the correct format: as that is not asked for in the question I'll leave as an exercise). Once the colour is set up, insert the appropriate special (noting the \edef will again mean at point of use there are no conditionals):

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

Following the color approach, a reset macro is also created using the appropriate special.

\edef\resetcolor{%
  \ifpdfmode
    \noexpand\pdfcolorstackpop
  \else
    \special{color pop}%
  \fi
}

The demo itself. The implementation above relies on a level of grouping inside boxes, which in LaTeX would be done by the \savebox 'wrapper' for \hbox (and so on). In plain that's not the case, so a colour-safe box needs a group. This could of course be put inside an appropriate set of wrapper macros:

\newbox\mybox
\setbox\mybox=\hbox{\begingroup\color{red}Red text\endgroup}
Surrounding text \box\mybox \space and more of it.
\bye

(Note: I've constructed the above in much the same way as I'd do using DocStrip for creating separate files. As DocStrip is not involved, this costs of some conditional/edef work.)

  • The above is more-or-less a direct copy of color or indeed the same implementation in l3drivers. – Joseph Wright Oct 15 '14 at 15:54
  • Note that other colour models can be covered: conversion code is present in the color package, but again that's probably an exercise here. – Joseph Wright Oct 15 '14 at 15:55
  • As noted in the other answers, this code is not really the tricky part: it's the entire 'don't colour stuff by accident' business you need to worry about! – Joseph Wright Oct 15 '14 at 16:19
  • There is an unwanted space generated in horizontal mode because of space after \pdfcolorstack\colorstackcnt pop. And another mistake: the \colorstackcnt is uninitialized. It means that it is zero. – wipet Oct 16 '14 at 21:14
  • @wipet I wasn't 100% sure if a space was needed after the keyword here, so had included one 'to be safe': I'd not tested fully. I'd not checked the full detail of the colour stack business, so was assuming it just required an integer: I've modified. – Joseph Wright Oct 16 '14 at 21:20
11

The latex graphics and color packages may be used in plain tex. http://www.ctan.org/pkg/miniltx

The maintainers of texdoc have chosen to show grfguide.pdf for texdoc color If you go texdoc color.pdf then you get the color package documentation, including fully indexed source listings.

plain tex has some virtues in being a simple format useful for teaching how to build a format, but I can't really imagine any way in which it could be said to be more flexible than latex. LaTeX doesn't remove any functionality.

  • "The \magnification command of Plain TeX has no counterpart in LaTeX" -L. Lamport, p.205 LaTeX User Guide and Reference Manual. I'm just tweaking you ;^) – Steven B. Segletes Oct 15 '14 at 12:49
  • @StevenB.Segletes You shouldn't believe everything you read – David Carlisle Oct 15 '14 at 12:50
  • Mayhaps I should have mentioned I used the broader definition of flexibility here. If the user knows how to build a format, then accessibility to certain flexibility is greatly improved. What I mean with this is that when the user has a better understanding of the low-level parts of the code, that will enhance control over the final print. – 1010011010 Oct 15 '14 at 12:53
  • @1010011010 perhaps, do you think if a user understands x86 machine code they have a better understanding of the C++ in the source of a web browser, and that the stability and maintainability of the system would be improved if assembler was injected in at random places? – David Carlisle Oct 15 '14 at 12:56
  • @1010011010 For color the main part of the work was not the color package itself it was going through the entire format and making sure all box access was "color safe" with extra groups to ensure that colour changes were correctly scoped. Even if you did the same for plain.tex it wouldn't really help as you can't control box assignements that users make. A major advantage in using a defined API above the bottom level (in any language) is that the access functions can be redefined, so for latex it should be enough to make the kernel colour safe and the latex \sbox command – David Carlisle Oct 15 '14 at 13:05
6

I've implemented full color stuff in my OPmac package for plainTeX. So I know, where are problems.

You can put the color selector to the typesetting material simply using \pdfliteral or \special but you have to keep in mind that the color is changed from this point to the end of page independent on grouping / paragraphs etc. from TeX point of view. For example \pdfliteral{1 0 0 r} means that all the text from this point to the end of the page (including footline, page number etc.) is red and the next page is reinitialized black. If you print something in the box which cannot break to more pages, then the

\hbox{\pdfliteral{1 0 0 r}Something in red\pdfliteral{0 g}}

is sufficient. But if the color can break into more pages or if you need the color stack (i.e the possibility to return to the previous color -- no explicitly Black) then you have to correct the headline/footline in \plainoutput and you have to implement color managing system over pages, managing colors stack etc. Moreover, there are two types of color selectors in PDF: for strokes and for fills. You can manage them independently or set both to the same color everywhere.

I've described all these features from implementation point of view in my technical documantation for OPmac: opmac-d.pdf, but it is only in Czech, sorry.

  • This sounds really good. Is there anything planned for an English translation of the documentation? – 1010011010 Oct 15 '14 at 14:45
  • 2
    If you are using pdfTeX, wouldn't you normally want the colour stack active in your example (assuming a recent enough pdfTeX)? (\pdfcolorstack <number> push <current colour> and so on.) – Joseph Wright Oct 15 '14 at 14:58
  • @1010011010 I have a lot of plans:). English translation is between them. Maybe students in my course will help me. English isn't my hobby. – wipet Oct 15 '14 at 20:14
  • @JosephWright I know \pdfcolorstack primitve. But OPmac doesn't use it because macros here are older than this primitive. Macro in OPmac implements its own color stack. The documentation about \pdfcolorstack was missing until 2013. – wipet Oct 16 '14 at 6:03
  • @wipet Yes, sure, I understand that would have been the case when it was developed but I meant that for a solution today you would naturally use the stack if available. – Joseph Wright Oct 16 '14 at 6:08
4

I tried to rewrite macros written by Joseph Wright in order they are more readable. His macros are less legible because of 1) redundant expandafters, begingroups csnames etc. when testing of the existence of the primitives and 2) usage of \edef for two variants of macros instead of usage of \ifpdfmode only once.

The comments are the same as in the Josephs answer.

\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

We need to set the pagenumber to black, if the color breaks to more pages:

\footline={\color{black}\hss\tenrm\folio\hss}

And the test:

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

Edit My first advice about making pagenumber black was only a simple introduction to the new problem. Now, we can remove the line \footline=... from our code and we will do things more conceptual.

We need to redefine \plainoutput in order to the \headline, \footline \topins and \footins are initialized by black color at every page. To do this, we set \currentcolor to \colorblack locally in output routine and we need to surround the \makeheadline, \makefooline, \unvbox\topins and \footnoterule\unvbox\footins by \pdfcolorstackpush, \pdfcolorstackpop pair. It means the following redefinition:

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

Note The synchronization of color stack with TeX grouping mechanism is implemented via \aftergroup and this is sometimes fragile. Joseph mentioned that the problem is in \setbox=\hbox{...\aftergroup\token...} because the \aftergroup token is processed after the box is set thus the \pdfcolorstackpop is inserted into the material where \setbox is used and not inside the \hbox. Thus we need to write

\setbox0=\hbox{{\color{red}text}}

The second example, where it is fragile, is \footnote*{\color{green}text} but you can re-define \footnote to make things more comfortable for user.

Note2 PDFTeX offers more than one stack and PDF specification gives two types of color selectors: 1 0 0 r for fills and 1 0 0 R for strokes. The example above uses both selectors in parallel (like in color.sty) but we can initialize second independent color stack for the second color selector and give to the user the possibility to select the right color selector (for text or for lines) like OPmac does it. But the problem is here: there are no more independent color stacks when xdvipdfmx is used. And the implementation of two independent color stacks at macro level is slightly more complicated (OPmac does this because its macros are older than \pdfcolorstack primitive).

  • \folio is a new command in your most recent adaptation. Could elaborate on its functionality in your post? – 1010011010 Oct 16 '14 at 21:56
  • @1010011010 I don't understand your comment. \folio is defined in plain TeX an I've tried the code from my post in plain TeX and without problems. The original content of \footline was changed only by adding \color{black}. – wipet Oct 17 '14 at 6:13
  • 2
    @wipet You need \begingroup\expandafter\expandafter\expandafter\endgroup\ifx\csname color#1\endcsname to avoid adding various \color... names to the hash table and equal to \relax for undefined colours. – Joseph Wright Oct 17 '14 at 7:56

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.