summaryrefslogtreecommitdiff
path: root/macros/luatex/optex/colors.opm
blob: 90d3d6d7a3ecc304f60ab4dabe63c69dbab3b82e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
%% This is part of OpTeX project, see http://petr.olsak.net/optex

\_codedecl \colordef {Colors <2020-03-18>} % loaded 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 are here.
   \_cod -----------------------------

\_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\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\White     {\_setgreycolor{1}}
\_def\Black     {\_setgreycolor{0}}

   \_doc -----------------------------
   By default, `\set/cmyk/rgb/grey/color` macros expands to `\_setcolor{<pdf-primitive>}` 
   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.
   \_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}}
\_public \setcmykcolor \setrgbcolor \setgreycolor ;

   \_doc -----------------------------
   The `\onlyrgb` declaration redefines `\_formatcmyk` in ordet it expands
   to its conversion to RGB <pdf-primitive>. This conversion is done by
   the `\_cmyktorgb` macro. Moreover, `\onlyrgb` re-defines three basic RGB
   colors for RGB color space and re-declares `\_colordef` as `\_rgbcolordef`.
   The `\onlycmyk` macro does a similar work, it re-defines `\_formatrgb`
   macro. The Grey color space is unnchanged and works in both main
   settings (RGB or CMYK) without collisions.
   The `\_fillstroke` uses the same color for fills and strokes.
   If only fills are needed to declare do `\def\_fillstroke#1#2{#1}`.
   If only strokes are needed to declare do `\def\_fillstroke#1#2{#2}`.
   \_cod -----------------------------

\_def\_fillstroke#1#2{#1 #2}
\_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}}}
\_public \onlyrgb \onlycmyk ;

   \_doc -----------------------------
   The `\_setcolor` macro redefines empty `\_ensureblack` macro (used in
   output routine for headres and footers) to `\_encureblackA` which keeps
   Black at start ot its parameter and retunrs to the current color at the
   end of its parameter. Then 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 current color to your macro  by `\let\yourmacro=\_currentcolor` 
   and you can return to this color by the command `\_setcmykcolor\yourmacro`.
   \_cod -----------------------------

\_protected\_def \_setcolor #1{\_global\_let\_ensureblack=\_ensureblackA
   \_iflocalcolor \_edef\_currentcolor{#1}\_colorstackpush\_currentcolor 
                  \_aftergroup\_colorstackpop
   \_else         \_xdef\_currentcolor{#1}\_colorstackset\_currentcolor \_fi
}
\_def\_pdfblackcolor{0 g 0 G}
\_edef\_currentcolor{\_pdfblackcolor}
\_def\_ensureblackA#1{\_global\_let\_openfnotestack=\_openfnotestackA
   \_colorstackpush\_pdfblackcolor #1\_colorstackpop}

   \_doc -----------------------------
   The colorstack is initialized here and 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}}

   \_doc -----------------------------
   We need to open a special color stack for footnotes, because footnotes
   can follow on next pages and their colors are independent on colors
   used in man page-body.
   \_cod -----------------------------

%\_mathchardef\_fnotestack=\_pdfcolorstackinit page {0 g 0 G}
% must be in \everyjob^^^
\_def \_openfnotestackA {\_pdfcolorstack\_fnotestack current}

   \_doc -----------------------------
   We use lua codes for RGB to CMYK or CMYK to RGB conversions and for
   addition color components in the `\colordef` macro.
   `\_rgbtocmyk <R> <G> <B> ;` expands to <C> <M> <Y> <K>.
   `\_cmyktorgb <C> <M> <Y> <K> ;` expands to <R> <G> <B>.
   The `\_colorcrop`, `\_colordefFin` and `\_douseK` are auxiliary macros
   used in `\colordef`. The `\colorcrop` rescales color components in order
   to they are in $[0,1]$ interval. The `\colordefFin` expands to the values
   accumulated in Lua code `color_C`, `color_M`, `color_Y` and `color_K`.
   The `\_douseK` applies `\useK` to CMYK components.
   \_cod -----------------------------

\_def\_rgbtocmyk #1 #2 #3 ;{%
   \_ea \_stripzeros \_detokenize \_ea{\_directlua{
      local kr = math.max(#1,#2,#3)
      if (kr==0) then
         tex.print('0. 0. 0. 1 ;')
      else
         tex.print(string.format('\_pcent.3f \_pcent.3f \_pcent.3f \_pcent.3f ;',
            (kr-#1)/kr, (kr-#2)/kr, (kr-#3)/kr, 1-kr))
      end
}}}
\_def\_cmyktorgb #1 #2 #3 #4 ;{%
   \_ea \_stripzeros \_detokenize \_ea{\_directlua{
      local kr = 1-#4
      tex.print(string.format('\_pcent.3f \_pcent.3f \_pcent.3f ;',
         (1-#1)*kr, (1-#2)*kr, (1-#3)*kr))
}}}
\_def\_colorcrop{\_directlua{
   local m=math.max(color_C, color_M, color_Y, color_K)
   if (m>1) then
      color_C=color_C/m  color_M=color_M/m  color_Y=color_Y/m color_K=color_K/m
   end
}}
\_def\_colordefFin{\_colorcrop \_ea \_stripzeros \_detokenize \_ea{\_directlua{
   tex.print(string.format('\_pcent.3f \_pcent.3f \_pcent.3f \_pcent.3f ;',
      color_C, color_M, color_Y, color_K))
}}}
\_def\_douseK{\_colorcrop \_directlua{
   kr=math.min(color_C, color_M, color_Y)
   if (kr>=1) then
      color_C=0  color_M=0  color_Y=0  color_K=1
   else
      color_C=(color_C-kr)/(1-kr)  color_M=(color_M-kr)/(1-kr)
      color_Y=(color_Y-kr)/(1-kr)  color_K=math.min(color_K+kr,1)
   end
}}

   \_doc -----------------------------
   We have a problem with the `%.3f` directive in Lua code. It prints trailed
   zeros: (0.300 instead desired 0.3) but we want to save PDF file space. The macro
   `\_stripzeros` removes these trailing zeros at expand processor
   level. So `\_stripzeros 0.300 0.400 0.560 ;` expands to `.3 .4 .56`.
   \_cod -----------------------------

\_def\_stripzeros #1.#2 #3{\_ifx0#1\_else#1\_fi.\_stripzeroA #2 0 :%
    \_ifx;#3\_else \_space \_ea\_stripzeros\_ea#3\_fi}
\_def\_stripzeroA #10 #2:{\_ifx^#2^\_stripzeroC#1:\_else \_stripzeroB#1 0 :\_fi} 
\_def\_stripzeroB #10 #2:{\_ifx^#2^\_stripzeroC#1:\_else #1\_fi}
\_def\_stripzeroC #1 #2:{#1}

   \_doc -----------------------------
   The `\rgbcolordef` and `\cmykcolordef` use common macro
   `\_commoncolordef` with different first four parameters.
   The `\_commoncolordef <selector><K><R><G><what-define>{<data>}` does the
   real work. It initializes the Lua variables for summation. 
   It expands <data> in the group where color selectors have
   special meaning, then it adjusts the resulting string by `\replstring`
   and runs it. Example shows how the <data> are processed:
   \begtt
   input <data>: ".3\Blue +.6^\KhakiC \useK -\Black"
   expanded to:  ".3 !=K 1 1 0 0 +.6^!=R .804 .776 .45 \_useK -!=G 0"
   adjusted to:  "\_addcolor .3!=K 1 1 0 0 \_addcolor .6!^R .804 .776 .45
                  \_useK \_addcolor -1!=G 0"  
   and this is processed.
   \endtt
   `\_addcolor <coef.>!<mod><type>` expands to `\_addcolor:<mod><type> <coef>`
   for example to `\_addcolor:=K <coef>` followed by one or three or four
   numbers (depending on <type>). <mod> is `=` (use as is) or `^` (use
   complementary color). <type> is `K` for CMYK, `R` for RGB and `G` for
   GREY color space. Uppercase <type> informs that `\cmykcolordef` is
   processed and lowercase <type> informs that `\rgbcolordef` is processed.
   All variants of commands `\_addcolor:<mod><type>` are defined. All of
   them expand to `\_addcolorA <v1> <v2> <v3> <v4>` which adds the values of Lua
   variables. The `\rgbcolordef` uses `\_addcolorA <R> <G> <B> 0` and 
   `\cmkykcolordef` uses `\_addcolorA <C> <M> <Y> <K>`. So the Lua variable
   names are a little confusing when `\rgbcolordef` is processed. 

   Next, `\_commoncolordef` saves resulting values from Lua to `\_tmpb`
   using `\_colordefFin`. If `\rgbcolordef` is processed, then we must to
   remove the last <K> component which is in the format `.0` in such case.
   The `\_stripK` macro does it.
   Finaly, the <what-define> is defined as `<selector>{<expanded _tmpb>}`.
   \_cod -----------------------------

\_def\_rgbcolordef  {\_commoncolordef \_setrgbcolor  krg}
\_def\_cmykcolordef {\_commoncolordef \_setcmykcolor KRG}
\_def\_commoncolordef#1#2#3#4#5#6{%
  \_begingroup
     \_directlua{color_C=0 color_M=0 color_Y=0 color_K=0}%
     \_def\_setcmykcolor##1{!=#2 ##1 }%
     \_def\_setrgbcolor ##1{!=#3 ##1 }%
     \_def\_setgreycolor##1{!=#4 ##1 }%
     \_let\_useK=\_relax
     \_edef\_tmpb{+#6}%
     \_replstring\_tmpb{+}{\_addcolor}\_replstring\_tmpb{-}{\_addcolor-}% 
     \_replstring\_tmpb{^!=}{!^}\_replstring\_tmpb{-!}{-1!}%
     \_ifx K#2\_let\_useK=\_douseK \_fi
     \_tmpb
     \_edef\_tmpb{\_colordefFin}%
     \_ifx k#2\_edef\_tmpb{\_ea\_stripK \_tmpb;}\_fi
  \_ea\_endgroup
  \_ea\_def\_ea#5\_ea{\_ea#1\_ea{\_tmpb}}%
}
\_def\_addcolor#1!#2#3{\_cs{addcolor:#2#3}#1}
\_def\_addcolorA #1 #2 #3 #4 #5 {%
   \_def\_tmpa{#1}\_ifx\_tmpa\_empty \_else \_edef\_tmpa{\_tmpa*}\_fi
   \_directlua{color_C=math.max(color_C+\_tmpa#2,0) 
               color_M=math.max(color_M+\_tmpa#3,0)
               color_Y=math.max(color_Y+\_tmpa#4,0)
               color_K=math.max(color_K+\_tmpa#5,0)
}}
\_sdef{addcolor:=K}#1 #2 #3 #4 #5 {\_addcolorA #1 #2 #3 #4 #5 }
\_sdef{addcolor:^K}#1 #2 #3 #4 #5 {\_addcolorA #1 (1-#2) (1-#3) (1-#4) #5 }
\_sdef{addcolor:^G}#1 #2 {\_addcolorA #1 0 0 0 #2 }
\_sdef{addcolor:=G}#1 #2 {\_addcolorA #1 0 0 0 (1-#2) }
\_sdef{addcolor:=R}#1 #2 #3 #4 {%
   \_edef\_tmpa{\_noexpand\_addcolorA #1 \_rgbtocmyk #2 #3 #4 ; }\_tmpa
}
\_sdef{addcolor:^R}#1 #2 #3 #4 {\_cs{addcolor:=R}#1 (1-#2) (1-#3) (1-#4) }

\_sdef{addcolor:=k}#1 #2 #3 #4 #5 {%
   \_edef\_tmpa{\_noexpand\_addcolorA #1 \_cmyktorgb #2 #3 #4 #5 ; 0 }\_tmpa
}
\_sdef{addcolor:^k}#1 #2 #3 #4 #5 {\_cs{addcolor:=k}#1 (1-#2) (1-#3) (1-#4) #5 }
\_sdef{addcolor:^g}#1 #2 {\_addcolorA #1 (1-#2) (1-#2) (1-#2) 0 }
\_sdef{addcolor:=g}#1 #2 {\_addcolorA #1 #2 #2 #2 0 }
\_sdef{addcolor:=r}#1 #2 #3 #4 {\_addcolorA #1 #2 #3 #4 0 }
\_sdef{addcolor:^r}#1 #2 #3 #4 {\_addcolorA #1 (1-#2) (1-#3) (1-#4) 0 }
\_def\_stripK#1 .0;{#1}
\_let\_colordef=\_cmykcolordef  % default \_colordef is \_cmykcolordef

   \_doc -----------------------------
   Public versions of `\colordef` and `\useK` macros are declared using 
   `\_def`, because the internal versions `\_colordef` and `\_useK` are
   changed during processing.
   \_cod -----------------------------

\_def \useK{\_useK}
\_def \colordef {\_colordef}
\_public \cmykcolordef \rgbcolordef ;

   \_doc -----------------------------
   The \LaTeX/ file `x11nam.def` is read by `\morecolors`. The numbers
   0,1,2,3,4 are trasformed to letters O, <none>, B, C, D in the name of the
   color. Colors defined already are not re-defined. The empty \_showcolor`
   macro should be re-defined for color catalog printing. For example:
   \begtt
   \def\vr{\vrule height10pt depth2pt width20pt}
   \def\_showcolor{\hbox{\tt \_bslash\_tmpb: \csname \_tmpb\endcsname \vr}\space\space}
   \typosize[11/14] \begmulti 4
   \morecolors
   \endmulti
   \endtt 
   \_cod -----------------------------

\_def\_morecolors{%
   \_long\_def\_tmp##1\preparecolorset##2##3##4##5{\_tmpa ##5;,,,;} 
   \_def\_tmpa##1,##2,##3,##4;{\_ifx,##1,\_else 
      \_def\_tmpb{##1}\_replstring\_tmpb{1}{}\_replstring\_tmpb{2}{B}% 
      \_replstring\_tmpb{3}{C}\_replstring\_tmpb{4}{D}\_replstring\_tmpb{0}{O}%
      \_ifcsname \_tmpb\_endcsname \_else 
          \_sdef{\_tmpb}{\_setrgbcolor{##2 ##3 ##4}}\_showcolor\_fi 
      \_ea\_tmpa\_fi
   } 
   \_ea\_tmp\_input x11nam.def
}
\_let\_showcolor=\_relax % re-define it if you want to print a color catalog
\_public \morecolors ;

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

The colors have different behavior than fonts. A 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 totally independent on \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 to return back to black color
using `\Black` manualy.

By default, \OpTeX/ sets `\localcolor`. It means that the typesetting
returns back to a previous color at the end of current group, so you cannot
write `\Black` explicitly. This is implemented using `\afterroup` feature.
There is a limitiation of this feature: when a color selector is used in a
group of a box, which is saved by `\setbox`, then the activity or
recontruction of previous color are processed at `\setbox` time, no in the
box itself. You must to correct it by double group: 
\begtt 
\setbox=\hbox{\Red something}   % bad: the \Black is done after \setbox 
\setbox=\hbox{{\Red something}} % good: the \Black is done after group inside the box 
\endtt
  
The implementation of colors is based on colorstack, so the current color
can follow acros 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.

Macros `\setcmykcolor{<C> <M> <Y> <K>}` or `\setrgbcolor{<R> <G> <B>}`
or `\_setgreycolor{<Grey>}` should be used in color selectors or user can
specify these macros explicitly.

The color mixing processed by `\colordef` is done in the substractive color
model CMYK. If the result has a component greater than 1 then all
components are multiplied by a coefficient in order to maximal component is
equal to 1.

You can move a common amount of CMY components (i.e. their minimum) to the
$K$ component. This saves the color tonners and the result is more true.
This should be done by `\useK` command at the end of a linear combination
used in `\colordef`. For example 
$$
  \colordef \myColor {.3\Green + .4\Blue \useK}
$$
The `\useK` command exactly does:
$$
  k' =\min(C,M,Y), \ C=(C-k')/(1-k'), \ M=(M-k')/(1-k'), \ Y=(Y-k')/(1-k'), \
  K = \min(1,K+k').
$$

You can use minus instead plus in the linear combination in `\colordef`. The
given color is substracted in such case and the negative components are
rounded to zero immediately. For example
\begtt
\colordef \Color {\Brown-\Black} 
\endtt
can be used for removing black component from the color. You can use
the `-\Black` trick after `\useK` command in order to remove grey components
occured during color mixing.

Finally, you can use `^` immediately preceeded before macro name of the
color. Then the complementary color is used here.
\begtt
\colordef \mycolor {\Grey + .6^\Blue} % the same as \colordef\mycolor{\Grey+.6\Yellow} 
\endtt

The `\rgbcolordef` can be used to mix colors in additive color model RGB.
If `\onlyrgb` is declared, then `\colordef` works as `\rgbcolordef`.

If a CMYK to RGB or RGB to CMYK conversion is needed then no ICC profiles are
supposed, but only the following simple formulae are used
$$
\displaylines{
   \hbox{CMYK to RGB:}\quad
   R = (1-C)(1-K), \ G = (1-M)(1-K), \ B = (1-Y)(1-K). \cr
   \hbox{RGB to CMYK:}\quad
   K'=\max(R,G,B), \ C=(K'-R)/K', \ M=(K'-G)/K', \ Y=(K'-B)/K', \ K=1-K'. 
}
$$
The RGB to CMYK conversion is invoked when a color is declared using `\setrgbcolor`
and it is used in `\colordef` or if it is printed when `\onlycmyk` is declared. 
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.