Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle color using attributes #57

Closed
wants to merge 60 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
d7c6c4b
Allocation of Lua functions (pseudoprimitives)
vlasakm Jun 22, 2021
c2b3d69
Handle color using attributes
vlasakm Jun 22, 2021
e3e46e8
test branch colors
olsak Jun 24, 2021
c34e9f9
add debug print
vlasakm Jun 24, 2021
8c40acd
Perform color setting in TeX
vlasakm Jun 27, 2021
750a557
Only set stroke color when necessary
vlasakm Jun 27, 2021
834d3e7
Add back support for \onlyrgb and \onlycmky
vlasakm Jun 27, 2021
e12b8c3
\onlyrgb, \onlycmyk corrected
olsak Jun 28, 2021
d26f6f9
branch marked in the banner
olsak Jun 28, 2021
3492b66
grouping in \table items changed
olsak Jun 29, 2021
83d211e
Define \preshipout and use callback
vlasakm Jun 29, 2021
36e0562
Simplify \incircle thanks to attributes
vlasakm Jun 29, 2021
3ac7e6d
Remove unnecessary grouping in \coloron
vlasakm Jun 26, 2021
306a467
Implement (no)localcolor in terms of \_colorprefix
vlasakm Jun 29, 2021
98f48a7
Save a few bytes in manually specified colors
vlasakm Jun 29, 2021
ab7003d
Fix typo
vlasakm Jun 29, 2021
ce57344
Prepare for luaotfload's color font feature
vlasakm Jun 29, 2021
fb457bb
Set luaotfload's current handler to use attributes
vlasakm Jun 29, 2021
324d1f8
documentation actualized
olsak Jun 30, 2021
ba74a8e
Remove unneeded local assignments, minor cleanup
vlasakm Jun 30, 2021
c6b9784
Use private variants of commands
vlasakm Jun 30, 2021
198c865
Add explanation of stroke color handling
vlasakm Jun 30, 2021
d4952b2
Improve luaotfload color handler
vlasakm Jun 30, 2021
d48c2d5
subsections in optex.lua added
olsak Jul 1, 2021
68c6ea3
colors.opm: shortening of documentation
olsak Jul 1, 2021
cfec5d7
Make "color change needed" calculation more robust
vlasakm Jul 1, 2021
1eb51b2
Don't care about the color of PDF literals
vlasakm Jul 1, 2021
a26c350
Trick 0004: annoying spaces removed
vlasakm Jul 1, 2021
9620813
Trick 0004: convert to new \_setcolor
vlasakm Jul 1, 2021
e81a2c6
Trick 0004: remove unnecessary grouping
vlasakm Jul 1, 2021
4a0e8c6
Trick 0004: use bp to prevent rounding
vlasakm Jul 1, 2021
7eea14e
Trick 0004: fix bugs
vlasakm Jul 1, 2021
cb1281b
Trick 0004: better safe than sorry (0.3bp overlap)
vlasakm Jul 1, 2021
44cd823
Fix example in tables.opm
vlasakm Jul 1, 2021
adc30e7
Fix mistake, small improvements
vlasakm Jul 1, 2021
a8e33d3
10pt is better in the \morecolors example
olsak Jul 2, 2021
5de705e
Remove debug print
vlasakm Jul 2, 2021
eb5bc02
Fix coloring of leader rules
vlasakm Jul 2, 2021
eb1b3f9
OpTeX trick 0063 added
olsak Jul 3, 2021
8365aa4
Trick 0063: use local, even if its only debugging
vlasakm Jul 3, 2021
f36feaa
Update documentation for `colorize`
vlasakm Jul 3, 2021
532b0c9
Finally handle discretionary nodes
vlasakm Jul 4, 2021
57e619a
Simplify `is_color_needed` a little bit
vlasakm Jul 4, 2021
d5c26a9
Spare a call to `colorize` for no replacement list
vlasakm Jul 4, 2021
23d94f9
Trick 0004: update documentation
vlasakm Jul 6, 2021
104f4c4
Fix OpTeX tricks info about colorstacks
vlasakm Jul 6, 2021
409c2d9
Add generic creator of pre-shipout injectors
vlasakm Jul 8, 2021
0314851
Add transparency pre-shipout injector
vlasakm Jul 8, 2021
bc6482b
Add font outline pre-shipout injector
vlasakm Jul 8, 2021
891dca1
Manage graphics states
vlasakm Jul 9, 2021
9137981
Use the new ExtGState management
vlasakm Jul 9, 2021
cb273c4
Use double colon for the color->attribute mapping
vlasakm Jul 11, 2021
0657980
Attempt to improve color documentation
vlasakm Jul 11, 2021
43bfbaa
Revert transparency etc. (to be an OpTeX trick)
vlasakm Jul 11, 2021
a9e64d8
Delete unneeded `node.subtype`
vlasakm Jul 11, 2021
befddab
Make `pdfliteral` available outside of `optex.lua`
vlasakm Jul 14, 2021
6fd6316
Fix luaotfload hook
vlasakm Jul 14, 2021
a336ff7
Add OpTeX trick 0064
vlasakm Jul 14, 2021
5019077
Don't ever reset color globally
vlasakm Jul 14, 2021
a00db07
Fix double colons yet again
vlasakm Jul 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ OpTeX including development versions.

See http://petr.olsak.net/optex/

branch colors

212 changes: 108 additions & 104 deletions optex/base/colors.opm
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@

\_codedecl \colordef {Colors <2021-05-28>} % preloaded in format

\_doc -----------------------------
We declare internal boolean value \`\_iflocalcolor` ad do
\`\localcolor` as default.
\_cod -----------------------------

\_newifi \_iflocalcolor \_localcolortrue
\_protected\_def \_localcolor {\_localcolortrue}
\_protected\_def \_nolocalcolor {\_localcolorfalse}
\_public \localcolor \nolocalcolor ;

\_doc -----------------------------
The basic colors in CMYK
\`\Blue` \`\Red` \`\Brown` \`\Green` \`\Yellow` \`\Cyan` \`\Magenta`
Expand All @@ -21,103 +11,101 @@

\_def\Blue {\_setcmykcolor{1 1 0 0}}
\_def\Red {\_setcmykcolor{0 1 1 0}}
\_def\Brown {\_setcmykcolor{0 0.67 0.67 0.5}}
\_def\Brown {\_setcmykcolor{0 .67 .67 .5}}
\_def\Green {\_setcmykcolor{1 0 1 0}}
\_def\Yellow {\_setcmykcolor{0 0 1 0}}
\_def\Cyan {\_setcmykcolor{1 0 0 0}}
\_def\Magenta {\_setcmykcolor{0 1 0 0}}
\_def\Grey {\_setcmykcolor{0 0 0 0.5}}
\_def\LightGrey {\_setcmykcolor{0 0 0 0.2}}
\_def\Grey {\_setcmykcolor{0 0 0 .5}}
\_def\LightGrey {\_setcmykcolor{0 0 0 .2}}
\_def\White {\_setgreycolor{1}}
\_def\Black {\_setgreycolor{0}}

\_doc -----------------------------
By default, the \`\setcmykcolor` \`\setrgbcolor` and \`\setgreycolor`
macros with `{<componetns>}` parameter
expand to `\_setcolor{<pdf-primitive>}` using \`\_formatcmyk`
or \`\_formatrgb` or \`\_formatgrey` expandable macros.
For example `\setrgbcolor{1 0 0}` expands to `\_setcolor{1 0 0 rg 1 0 0 RG}`.\nl
We set both types of colors (for lines (`K` or `RG` or `G`) and for fills
(`r` or `rg` or `g`) together in the <pdf-primitive> command.
This is the reason why the \`\_fillstroke` uses both its parameters.
If only fills are needed you can do `\def\_fillstroke#1#2{#1}`.
If only strokes are needed you can do `\def\_fillstroke#1#2{#2}`.
expand to \^`\_setcolor``{<color-data>}{<fill-op>}{<stroke-op>}` where
<color-data> is <R> <G> <B> or <C> <M> <Y> <K> or <G> and
<fill-op> is color operator for filling, <stroke-op> is color operator
for stroking.
\_cod -----------------------------

\_def\_setcmykcolor#1{\_setcolor{\_formatcmyk{#1}}}
\_def\_setrgbcolor#1{\_setcolor{\_formatrgb{#1}}}
\_def\_setgreycolor#1{\_setcolor{\_formatgrey{#1}}}
\_def\_formatcmyk#1{\_fillstroke{#1 k}{#1 K}}
\_def\_formatrgb#1{\_fillstroke{#1 rg}{#1 RG}}
\_def\_formatgrey#1{\_fillstroke{#1 g}{#1 G}}
\_def\_fillstroke#1#2{#1 #2}
\_def\_setcmykcolor#1{\_setcolor{#1}kK}
\_def\_setrgbcolor#1{\_setcolor{#1}{rg}{RG}}
\_def\_setgreycolor#1{\_setcolor{#1}gG}
\_public \setcmykcolor \setrgbcolor \setgreycolor ;

\_doc -----------------------------
The \`\onlyrgb` declaration redefines \^`\_formatcmyk` in order it expands
to its conversion to RGB <pdf-primitive>. This conversion is done by
the \^`\_cmyktorgb` macro. Moreover, `\onlyrgb` re-defines three basic RGB
The \`\onlyrgb` declaration redefines \^`\setcmykcolor` to do conversion
to RGB just before \^`\_setcolor` is used.
The \`\onlycmyk` declaration redefines \^`\setrgbcolor` to do conversion
to CMYK just before \^`\_setcolor` is used.
Moreover, \^`\onlyrgb` re-defines three basic RGB
colors for RGB color space and re-declares \^`\colordef` as \^`\rgbcolordef`.
The \hbox{\`\onlycmyk`} macro does similar work, it re-defines \^`\_formatrgb`
macro. The Grey color space is unchanged and works in both main
settings (RGB or CMYK) without collisions.
\_cod -----------------------------

\_def\_onlyrgb{\_def\Red{\_setrgbcolor{1 0 0}}%
\_def\Green{\_setrgbcolor{0 1 0}}\_def\Blue{\_setrgbcolor{0 0 1}}%
\_let\_colordef=\_rgbcolordef
\_def\_formatrgb##1{\_fillstroke{##1 rg}{##1 RG}}%
\_def\_formatcmyk##1{\_fillstroke{\_cmyktorgb ##1 ; rg}{\_cmyktorgb ##1 ; RG}}}
\_def\_onlycmyk{\_def\_formatcmyk##1{\_fillstroke{##1 k}{##1 K}}%
\_def\_formatrgb##1{\_fillstroke{\_rgbtocmyk ##1 ; k}{\_rgbtocmyk ##1 ; K}}}
\_def\_setrgbcolor##1{\_setcolor{##1}{rg}{RG}}%
\_def\_setcmykcolor##1{\_ea\_setcolor\_ea{\_expanded{\_cmyktorgb ##1 ;}}{rg}{RG}}%
\_public \colordef \setrgbcolor \setcmykcolor ;}
\_def\_onlycmyk{%
\_let\_colordef=\_cmykcolordef
\_def\_setrgbcolor##1{\_ea\_setcolor\_ea{\_expanded{\_rgbtocmyk ##1 ;}}kK}%
\_def\_setcmykcolor##1{\_setcolor{##1}kK}%
\_public \colordef \setrgbcolor \setcmykcolor ;}
\_public \onlyrgb \onlycmyk ;

\_doc -----------------------------
The \`\_setcolor` macro redefines empty `\_ensureblack` macro (used in
output routine for headers and footers) to `\_ensureblackA` which sets
Black at the start of its parameter and returns to the current color at the
end of its parameter.

The current color is saved into `\_currentcolor` macro and colorstack is pushed.
Finally, the `\_colorstackpop` is initialized by `\aftergroup` if
`\localcolor` is declared.

You can save the current color to your macro by `\let\yourmacro=\_currentcolor`
and you can return to this color by the command `\_setcolor\yourmacro`.
The \`\_colorattr` for coloring is allocated and
\`\_setcolor``{<color-data>}{<fill-op>}{<stroke-op>}` is defined here.
This macro does `\_colorattr=`\`\_colorcnt` if the <color data> was not used
before and prepare mapping from this integer value to the <color data>
and increments \^`\_colorcnt`.
If the <color data> were used already, then \^`\_setcolor`
does `\_colorattr=<stored-value>`.
This work is done by the \`\_translatecolor` macro. The following mapping
macros are created:
\begtt \catcode`<=13
\_color::<data> <fill-op> ... expands to used <attribute-value>
\_color:<attribute-value> ... expands to <data> <fill-op>
\_color-s:<attribute-value> ... expands to <data> <stroke-op>
\endtt
The \`\_resetcolor` un-sets the color attribute, it means that default
color (black) shall be used.
\_cod -----------------------------

\_protected\_def \_setcolor #1{\_global\_let\_ensureblack=\_ensureblackA
\_iflocalcolor \_edef\_currentcolor{#1}\_colorstackpush\_currentcolor
\_aftergroup\_colorstackpop
\_else \_xdef\_currentcolor{#1}\_colorstackset\_currentcolor \_fi
\_newattribute \_colorattr
\_newcount \_colorcnt \_colorcnt=1 % allocations start at 1
\_protected\_def\_setcolor{\_colorprefix\_colorattr=\_translatecolor}
\_def\_resetcolor{\_colorattr=-"7FFFFFFF }
\_def\_translatecolor#1#2#3{\_ifcsname _color::#1 #2\_endcsname\_lastnamedcs\_relax
\_else
\_colorcnt
\_sxdef{_color::#1 #2}{\_the\_colorcnt}%
\_sxdef{_color:\_the\_colorcnt}{#1 #2}%
\_sxdef{_color-s:\_the\_colorcnt}{#1 #3}%
\_incr \_colorcnt
\_fi
}
\_def\_pdfblackcolor{0 g 0 G}
\_edef\_currentcolor{\_pdfblackcolor}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep this?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example

\_def\_pdfblackcolor{0 g}
\_def\_currentcolor{\_trycs{_color:\_the\_colorattr}{\_pdfblackcolor}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the current state, even with your suggestion added, the old (documented) idiom \let\yourmacro=\_currentcolor -> \_setcolor\yourmacro wouldn't really work - \_setcolor expects now something like {0}gG, while \cs{_color:\_the\_colorattr} would expand to 0 g.

I think that with the power of grouping, the concept of saving colors is not needed. But I am not sure about the right interface if it has to be kept.

\_def\_ensureblackA#1{\_global\_let\_openfnotestack=\_openfnotestackA
vlasakm marked this conversation as resolved.
Show resolved Hide resolved
\_colorstackpush\_pdfblackcolor #1\_colorstackpop}

\_doc -----------------------------
The colorstack is initialized here and the basic macros
\`\_colorstackpush`, \`\_colorstackpop` and \`\_colorstackset`
are defined here.
\_cod -----------------------------

\_mathchardef\_colorstackcnt=0 % Implicit stack usage
\_def\_colorstackpush#1{\_pdfcolorstack\_colorstackcnt push{#1}}
\_def\_colorstackpop{\_pdfcolorstack\_colorstackcnt pop}
\_def\_colorstackset#1{\_pdfcolorstack\_colorstackcnt set{#1}}
% Black is the default color.
\_sdef{_color::0 g}{0}
\_sdef{_color:0}{0 g}
\_sdef{_color-s:0}{0 G}

\_doc -----------------------------
We need to open a special color stack for footnotes because footnotes
can follow on the next pages and their colors are independent of colors
used in the main page-body. The \`\_openfnotestack` is defined as
\`\_openfnotestackA` when the \^`\_setcolor` is used first.
The \`\_fnotestack` is initialized in in `\everyjob` because the
initialization is not saved to the format.
We support concept of non-local color, i.e. all changes of the color
attribute are global by setting \`\_colorprefix` to `\global`.
\`\localcolor` is the default, i.e.\ \^`\_colorprefix` is `\relax`.\nl
You can write `\global\Red` if you want to have global setting of the
color.
\_cod -----------------------------

%\_mathchardef\_fnotestack=\_pdfcolorstackinit page {0 g 0 G} % must be in \everyjob
\_def \_openfnotestackA {\_pdfcolorstack\_fnotestack current}
\_protected\_def \_localcolor {\_let\_colorprefix=\_relax}
\_protected\_def \_nolocalcolor {\_let\_colorprefix=\_global}
\_public \localcolor \nolocalcolor ;
\_localcolor

\_doc -----------------------------
We use Lua codes for RGB to CMYK or CMYK to RGB conversions and for
Expand Down Expand Up @@ -297,7 +285,7 @@
\begtt
\def\vr{\vrule height10pt depth2pt width20pt}
\def\_showcolor{\hbox{\tt\_bslash\_tmpb: \csname\_tmpb\endcsname \vr}\space\space}
\begmulti 4 \typosize[11/14]
\begmulti 4 \typosize[10/14]
\morecolors
\endmulti
\endtt
Expand All @@ -319,35 +307,49 @@

\_endcode % -------------------------------------

The colors have different behavior than fonts. Marks (whatsits) with color
information are stored into PDF output and \TeX/ doesn't interpret them.
The PDF viewer (or PDF interpreter in a printer) reads these marks
and switches colors according to them. This
is independent of \TeX/ group mechanism. You can declare
`\nolocalcolor` at the beginning of the document, if you want this behavior.
In this case, if you set a color then you must return to the black color
using `\Black` manually.

By default, \OpTeX/ sets `\localcolor`. It means that the typesetting
returns to a previous color at the end of the current group, so you cannot
write `\Black` explicitly. This is implemented using the `\aftergroup` feature.
There is a limitation of this feature: when a color selector is used in a
group of a box, which is saved by `\setbox`, then the activity or
reconstruction of the previous color is processed at `\setbox` time, no in the
box itself. You must correct it by double group:
\begtt
\setbox0=\hbox{\Red text} % bad: \Black is done after \setbox
\setbox0=\hbox{{\Red text}} % good: \Black is done after group inside the box
\endtt

The implementation of colors is based on colorstack, so the current color
can follow across more pages. It is not so obvious because PDF viewer (or PDF
interpreter) manipulates with colors locally at each PDF page and it
initializes each PDF page with black on white color.
\secc Basic concept

Setting of color in PDF is handled by graphics operators which change the
graphics context. Colors for fills/strokes are distinguished, but apart from
that, only one color is active at time and is used for all material drawn by
following graphics operators, until next color is set. Each PDF content (e.g.
page or form XObject) has its own graphics context, that is initialized from
zero. Hence we have different concept of selecting fonts in \TeX/ (it
depends on \TeX/ groups but does not depends on pages) and color handling in
PDF.

\TeX/ itself has no concept of colors. Colors have always been handled by
inserting whatsits (either using `\special` for DVI or using
`\pdfliteral`/`\pdfcolorstack` for PDF). It is very efficient and \TeX/ doesn't
even have to know anything about colors, but it is also problematic in many
ways.

That is the reason why we decided to change color handling from
`\pdfcolorstack` to \LuaTeX/ attributes in version 1.04 of \OpTeX. Using
attributes, the color setting behaves exactly like font selection from \TeX/
point of view: it respects \TeX/ groups, colors can span more pages,
independent colors can be set for `\insert`s, etc. Moreover, once a material is
created (using `\setbox` for example) then it has its fonts and its colors
frozen and you can rely on it when you are using e.g. `\unhbox`. There are no
internal whatsits for colors which can interfere with other typesetting
material. In the end something like setting text to red (`{\Red text}`) should
have the same nice behavior like setting text to bold (`{\bf text}`).

\LuaTeX/ attributes can be set like count register -- one attribute holds one
number at a time. But the value of attribute is propagated to each created
typesetting element until the attribute is unset or set to another value. Very
much like the font property. We use one attribute \^`\_colorattr` for storing
the currently selected color (in number form).

Macros \^`\setcmykcolor``{<C> <M> <Y> <K>}` or \^`\setrgbcolor``{<R> <G> <B>}`
or\nl \^`\setgreycolor``{<Grey>}` should be used in color selectors or user can
specify these macros explicitly.
or\nl \^`\setgreycolor``{<Grey>}` are used in color selectors. These
macros expand to internal \^`\_setcolor` macro which sets the \^`\_colorattr`
attribute to an integer value and prepares mapping between this value and the real
color data. This mapping is used just before each `\shipout` in output routine.
The \^`\_preshipout` pseudo-primitive is used here, it converts attribute
values to internal PDF commands for selecting colors.

\secc Color mixing

The color mixing processed by the \^`\colordef` is done in the subtractive color
model CMYK. If the result has a component greater than 1 then all
Expand Down Expand Up @@ -405,6 +407,8 @@ and it is used in \^`\colordef` or if it is printed when \^`\onlycmyk` is declar
The CMYK to RGB conversion is invoked when a color is declared using \^`\setcmykcolor`
and it is used in \^`\rgbcolordef` or if it is printed when \^`\onlyrgb` is declared.

\secc Implementation

\_endinput

2021-05-28 \rgbcmykmap introduced
Expand Down
6 changes: 3 additions & 3 deletions optex/base/doc.opm
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
The lines in the listing mode have a yellow background.
\_cod -----------------------------

\_def\Yellow{\_setcmykcolor{0.0 0.0 0.3 0.03}}
\_def\Yellow{\_setcmykcolor{0 0 .3 .03}}

\_def\_printcodeline#1{\_advance \_maxlines by-1
\_ifnum \_maxlines<0 \_ea \_endverbprinting \_fi
Expand All @@ -137,7 +137,7 @@
\_indent \_printverblinenum #1\par}

\_def\_printfilename{\_hbox to0pt{%
\_hskip\_hsize\vbox to0pt{\_vss\_llap{\Brown\docfile}\_kern7.5pt}\_hss}%
\_hskip\_hsize\_vbox to0pt{\_vss\_llap{\Brown\docfile}\_kern7.5pt}\_hss}%
\_let\_printfilename=\_relax
}
\_everytt={\_let\_printverblinenum=\_relax}
Expand All @@ -153,7 +153,7 @@
\_def\docfile{}
\_def\_printdoc #1 {\_par \_def\docfile{#1}%
\_everytt={\_ttshift=-15pt \_let\_printverblinenum=\_relax}%
\_ea\_cod \input #1
\_ea\_cod \_input #1
\_everytt={\_let\_printverblinenum=\_relax}%
\_def\docfile{}%
}
Expand Down
1 change: 1 addition & 0 deletions optex/base/fonts-select.opm
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
\_directlua{%
require('luaotfload-main')
luaotfload.main()
optex_hook_into_luaotfload()
}%
\_gdef\_rfskipatX ##1" ##2\_relax{"##1"}%
\_global\_let \_doresizefont=\_doresizeunifont
Expand Down
Loading