From 87cddce361c3b477029d13b27bdaa57190b2d74b Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Sun, 15 Mar 2020 03:01:24 +0000 Subject: CTAN sync 202003150301 --- macros/luatex/optex/colors.opm | 361 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 macros/luatex/optex/colors.opm (limited to 'macros/luatex/optex/colors.opm') diff --git a/macros/luatex/optex/colors.opm b/macros/luatex/optex/colors.opm new file mode 100644 index 0000000000..52dd349f5e --- /dev/null +++ b/macros/luatex/optex/colors.opm @@ -0,0 +1,361 @@ +%% This is part of OpTeX project, see http://petr.olsak.net/optex + +\_codedecl \colordef {Colors <2020-03-07>} + + \_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{}` + We set both types of colors (for lines (`K` or `RG` or `G`) and for fills + (`r` or `rg` or `g`) together in the command. + \_cod ----------------------------- + +\_def\_setcmykcolor#1{\_setcolor{\_formatcmyk{#1}}} +\_def\_setrgbcolor#1{\_setcolor{\_formatrgb{#1}}} +\_def\_setgreycolor#1{\_setcolor{\_formatgrey{#1}}} +\_def\_formatcmyk#1{#1 k #1 K} +\_def\_formatrgb#1{#1 rg #1 RG} +\_def\_formatgrey#1{#1 g #1 G} +\_public \setcmykcolor \setrgbcolor \setgreycolor ; + + \_doc ----------------------------- + The `\onlyrgb` declaration redefines `\_formatcmyk` in ordet it expands + to its conversion to RGB . 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. + \_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{##1 rg ##1 RG}% + \_def\_formatcmyk##1{\_cmyktorgb ##1 ; rg \_cmyktorgb ##1 ; RG}} +\_def\_onlycmyk{\_def\_formatcmyk##1{##1 k ##1 K}% + \_def\_formatrgb##1{\_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{\_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 use lua codes for RGB to CMYK or CMYK to RGB conversions and for + addition color components in the `\colordef` macro. + `\_rgbtocmyk ;` expands to . + `\_cmyktorgb ;` expands to . + 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 \_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 \_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 \_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 {}` does the + real work. It initializes the Lua variables for summation. + It expands in the group where color selectors have + special meaning, then it adjusts the resulting string by `\replstring` + and runs it. Example shows how the are processed: + \begtt + input : ".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 !` expands to `\_addcolor: ` + for example to `\_addcolor:=K ` followed by one or three or four + numbers (depending on ). is `=` (use as is) or `^` (use + complementary color). is `K` for CMYK, `R` for RGB and `G` for + GREY color space. Uppercase informs that `\cmykcolordef` is + processed and lowercase informs that `\rgbcolordef` is processed. + All variants of commands `\_addcolor:` are defined. All of + them expand to `\_addcolorA ` which adds the values of Lua + variables. The `\rgbcolordef` uses `\_addcolorA 0` and + `\cmkykcolordef` uses `\_addcolorA `. 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 component which is in the format `.0` in such case. + The `\_stripK` macro does it. + Finaly, the is defined as `{}`. + \_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, , 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{ }` or `\setrgbcolor{ }` +or `\_setgreycolor{}` 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. + + -- cgit v1.2.3