summaryrefslogtreecommitdiff
path: root/macros/luatex/optex/base/colors.opm
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/optex/base/colors.opm')
-rw-r--r--macros/luatex/optex/base/colors.opm393
1 files changed, 393 insertions, 0 deletions
diff --git a/macros/luatex/optex/base/colors.opm b/macros/luatex/optex/base/colors.opm
new file mode 100644
index 0000000000..2745e0fc51
--- /dev/null
+++ b/macros/luatex/optex/base/colors.opm
@@ -0,0 +1,393 @@
+%% 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
+ \`\Blue` \`\Red` \`\Brown` \`\Green` \`\Yellow` \`\Cyan` \`\Magenta`
+ \`\Grey` \`\LightGrey` \`\White` and \`\Black`
+ are declared 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, 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}`.
+ \_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}
+\_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
+ colors for RGB color space and re-declares \^`\colordef` as \^`\rgbcolordef`.
+ The \hbox{\`\onlycmyk`} macro does a 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}}}
+\_public \onlyrgb \onlycmyk ;
+
+ \_doc -----------------------------
+ The \`\_setcolor` macro redefines empty `\_ensureblack` macro (used in
+ output routine for headres and footers) to `\_ensureblackA` which sets
+ Black at the start of its parameter and retunrs 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 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 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}}
+
+ \_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 the main page-body. The \`\_openfnotestack` is defined as
+ \`\_openfnotestackA` when the \^`\_setcolor` is used first.
+ The \`\_fnotestack` is initializedin in `\everyjob` because the
+ initialization is not saved to the format.
+ \_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.
+ The \`\_rgbtocmyk` `<R> <G> <B> ;` expands to `<C> <M> <Y> <K>` and
+ the \`\_cmyktorgb` `<C> <M> <Y> <K> ;` expands to `<R> <G> <B>`.
+ The \`\_colorcrop`, \`\_colordefFin` and \`\_douseK` are auxiliary macros
+ used in the \^`\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 it expands 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.
+ Finally, the `<what-define>` is defined as `<selector>{<expanded _tmpb>}`,
+ for example `\_setcmykclor{1 0 .5 .3}`.
+ \_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{+ }{+}\_replstring\_tmpb{- }{-}%
+ \_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 transformed 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}
+ \begmulti 4 \typosize[11/14]
+ \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` manually.
+
+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 `\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 previous color are 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.
+
+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.
+
+The color mixing processed by the \^`\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 shared 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
+\begtt
+\colordef \myColor {.3\Green + .4\Blue \useK}
+\endtt
+The `\useK` command exactly does:
+$$
+ \displaylines{
+ k' =\min(C,M,Y), \cr \ C=(C-k')/(1-k'), \ M=(M-k')/(1-k'), \ Y=(Y-k')/(1-k'), \cr
+ 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
+the following simple formulae are used
+(ICC profiles are not supported):
+$$
+\displaylines{
+ \hbox{CMYK to RGB:}\cr
+ R = (1-C)(1-K), \ G = (1-M)(1-K), \ B = (1-Y)(1-K). \cr
+ \hbox{RGB to CMYK:}\cr
+ 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.
+
+\_endinput
+
+2020-04-22 \replstring\tmpb{+ }{+}, {- }{-} added in \colordef, bug fixed
+2020-03-18 introduced