diff options
Diffstat (limited to 'Master/texmf-dist/tex/optex/base/colors.opm')
-rw-r--r-- | Master/texmf-dist/tex/optex/base/colors.opm | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/optex/base/colors.opm b/Master/texmf-dist/tex/optex/base/colors.opm new file mode 100644 index 00000000000..bbda496761e --- /dev/null +++ b/Master/texmf-dist/tex/optex/base/colors.opm @@ -0,0 +1,394 @@ +%% This is part of the 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 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 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`. + \_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 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. + \_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 the 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 \catcode`\<=13 + 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. 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. + +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 subtractive color +model CMYK. If the result has a component greater than 1 then all +components are multiplied by a coefficient in order to the 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 of 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 the black component from the color. You can use +the `-\Black` trick after `\useK` command to remove grey components +occurred during color mixing. + +Finally, you can use `^` immediately preceded before the 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 |