diff options
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3color.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3color.dtx | 197 |
1 files changed, 110 insertions, 87 deletions
diff --git a/macros/latex/contrib/l3kernel/l3color.dtx b/macros/latex/contrib/l3kernel/l3color.dtx index f77304a0a5..c6c8eb3262 100644 --- a/macros/latex/contrib/l3kernel/l3color.dtx +++ b/macros/latex/contrib/l3kernel/l3color.dtx @@ -2,7 +2,7 @@ % %% File: l3color.dtx % -% Copyright (C) 2017-2021 The LaTeX Project +% Copyright (C) 2017-2022 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2021-11-22} +% \date{Released 2022-01-12} % % \maketitle % @@ -249,6 +249,9 @@ % General selection of color is safe when split across pages: a stack is % used to ensure that the correct color is re-selected on the new page. % +% These commands set the current color (|.|): other more specialised functions +% such as fill and stroke selectors do \emph{not} adjust this value. +% % \begin{function}{\color_select:n} % \begin{syntax} % \cs{color_select:n} \Arg{color expression} @@ -281,9 +284,6 @@ % support this, and so color will need to be contained within a scope, such % as \cs{draw_begin:}/\cs{draw_end:}. % -% Note that the \emph{current color} is the fill color, as this is used for -% running text. -% % \begin{function}{\color_fill:n, \color_stroke:n} % \begin{syntax} % \cs{color_fill:n} \Arg{color expression} @@ -538,12 +538,15 @@ % \begin{macro}{\@@_select:nn} % Take an internal color specification and pass it to the driver. This code % is needed to ensure the current color but will also be used by the -% higher-level experimental material. +% higher-level material. % \begin{macrocode} \cs_new_protected:Npn \@@_select:N #1 { \exp_after:wN \@@_select:nn #1 } \cs_new_protected:Npn \@@_select:nn #1#2 - { \use:c { @@_backend_select_ #1 :n } {#2} } + { + \use:c { @@_backend_select_ #1 :n } {#2} + \group_insert_after:N \@@_backend_reset: + } % \end{macrocode} % \end{macro} % \end{macro} @@ -595,7 +598,7 @@ % % \subsection{Utility functions} % -% \begin{macro}[int, TF, EXP]{\@@_if_defined:n} +% \begin{macro}[TF, EXP]{\@@_if_defined:n} % A simple wrapper to avoid needing to have the lookup repeated in too many % places. % \begin{macrocode} @@ -632,33 +635,63 @@ % % \begin{macro}{\@@_convert:nnN, \@@_convert:VVN} % \begin{macro}{\@@_convert:nnnN, \@@_convert:nVnN, \@@_convert:nnVN} -% \begin{macro}[aux, EXP] +% \begin{macro}[EXP] % { +% \@@_convert_gray_gray:w % \@@_convert_gray_rgb:w % \@@_convert_gray_cmyk:w % \@@_convert_cmyk_gray:w % \@@_convert_cmyk_rgb:w +% \@@_convert_cmyk_cmyk:w % \@@_convert_rgb_gray:w +% \@@_convert_rgb_rgb:w % \@@_convert_rgb_cmyk:w % } -% \begin{macro}[aux, EXP]{\@@_convert_rgb_cmyk:nnnn} -% Model conversion is carried out using standard formulae, as described in -% the manual for \pkg{xcolor} (see also the \emph{PostScript Language -% Reference Manual}). +% \begin{macro}[EXP]{\@@_convert_rgb_cmyk:nnnn} +% Model conversion is carried out using standard formulae for base models, +% as described in the manual for \pkg{xcolor} (see also the \emph{PostScript +% Language Reference Manual}). For other models direct conversion might not +% be defined, so we go through the fallback models if necessary. % \begin{macrocode} \cs_new_protected:Npn \@@_convert:nnN #1#2#3 { \@@_convert:nnVN {#1} {#2} #3 #3 } \cs_generate_variant:Nn \@@_convert:nnN { VV } +\cs_generate_variant:Nn \exp_last_unbraced:Nf { c } \cs_new_protected:Npn \@@_convert:nnnN #1#2#3#4 { \tl_set:Nx #4 { - \cs_if_exist:cTF { @@_convert_ #1 _ #2 :w } - { \use:c { @@_convert_ #1 _ #2 :w } #3 \s_@@_stop } - { \use:c { c_@@_fallback_ #2 _tl } } + \cs_if_exist_use:cTF { @@_convert_ #1 _ #2 :w } + { #3 \s_@@_stop } + { + \cs_if_exist:cTF { @@_convert_ \use:c { c_@@_fallback_ #1 _tl } _ #2 :w } + { + \exp_last_unbraced:cf + { @@_convert_ \use:c { c_@@_fallback_ #1 _tl } _ #2 :w } + { \use:c { @@_convert_ #1 _ \use:c { c_@@_fallback_ #1 _tl } :w } #3 \s_@@_stop } + \s_@@_stop + } + { + \exp_last_unbraced:cf + { @@_convert_ \use:c { c_@@_fallback_ #2 _tl } _ #2 :w } + { + \cs_if_exist_use:cTF { @@_convert_ #1 _ \use:c { c_@@_fallback_ #2 _tl } :w } + { #3 \s_@@_stop } + { + \exp_last_unbraced:cf + { @@_convert_ \use:c { c_@@_fallback_ #1 _tl } _ \use:c { c_@@_fallback_ #2 _tl } :w } + { \use:c { @@_convert_ #1 _ \use:c { c_@@_fallback_ #1 _tl } :w } #3 \s_@@_stop } + \s_@@_stop + } + } + \s_@@_stop + } + } } } \cs_generate_variant:Nn \@@_convert:nnnN { nV , nnV } +\cs_new:Npn \@@_convert_gray_gray:w #1 \s_@@_stop + { #1 } \cs_new:Npn \@@_convert_gray_rgb:w #1 \s_@@_stop { #1 ~ #1 ~ #1 } \cs_new:Npn \@@_convert_gray_cmyk:w #1 \s_@@_stop @@ -669,6 +702,8 @@ % \begin{macrocode} \cs_new:Npn \@@_convert_rgb_gray:w #1 ~ #2 ~ #3 \s_@@_stop { \fp_eval:n { 0.3 * #1 + 0.59 * #2 + 0.11 * #3 } } +\cs_new:Npn \@@_convert_rgb_rgb:w #1 \s_@@_stop + { #1 } % \end{macrocode} % The conversion from |rgb| to |cmyk| is the most complex: a two-step % procedure which requires \emph{black generation} and \emph{undercolor @@ -697,6 +732,8 @@ \fp_eval:n { 1 - min ( 1 , #2 + #4 ) } \c_space_tl \fp_eval:n { 1 - min ( 1 , #3 + #4 ) } } +\cs_new:Npn \@@_convert_cmyk_cmyk:w #1 \s_@@_stop + { #1 } % \end{macrocode} % \end{macro} % \end{macro} @@ -728,9 +765,9 @@ % \begin{macro}{\@@_parse_gray:n, \@@_parse_std:n} % \begin{macro}{\@@_parse_break:w} % \begin{macro}{\@@_parse_end:} -% \begin{macro}[aux, EXP]{\@@_parse_mix:Nnnn, \@@_parse_mix:NVVn} -% \begin{macro}[aux, EXP]{\@@_parse_mix:nNnn} -% \begin{macro}[aux, EXP] +% \begin{macro}[EXP]{\@@_parse_mix:Nnnn, \@@_parse_mix:NVVn} +% \begin{macro}[EXP]{\@@_parse_mix:nNnn} +% \begin{macro}[EXP] % { % \@@_parse_mix_gray:nw , % \@@_parse_mix_rgb:nw , @@ -1222,13 +1259,13 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\@@_select:} +% \begin{macro}{\@@_finalise_current:} % A backend-neutral location for \enquote{last minute} manipulations before % handing off to the backend code. We set the special |.| syntax here: this % will therefore always be available. The finalisation is separate from the % main function so it can also be applied to \emph{e.g.}~page color. % \begin{macrocode} -\cs_new_protected:Npx \@@_select: +\cs_new_protected:Npx \@@_finalise_current: { \tl_set:Nx \exp_not:c { l_@@_named_ . _tl } { \exp_not:N \@@_model:N \exp_not:N \l_@@_current_tl } @@ -1236,7 +1273,6 @@ \prop_put:NVx \exp_not:c { l_@@_named_ . _prop } \exp_not:c { l_@@_named_ . _tl } { \exp_not:N \@@_values:N \exp_not:N \l_@@_current_tl } - \@@_select:N \exp_not:N \l_@@_current_tl } % \end{macrocode} % \end{macro} @@ -1254,13 +1290,15 @@ \cs_new_protected:Npn \color_select:n #1 { \@@_parse:nN {#1} \l_@@_current_tl - \@@_select: + \@@_finalise_current: + \@@_select:N \l_@@_current_tl } \cs_new_protected:Npn \color_select:nn #1#2 { \@@_select_main:Nw \l_@@_current_tl #1 / / \s_@@_mark #2 / / \s_@@_stop - \@@_select: + \@@_finalise_current: + \@@_select:N \l_@@_current_tl } % \end{macrocode} % If the first color model is the fixed one, or if there is no fixed @@ -1692,12 +1730,12 @@ % % \begin{variable} % {\c_@@_fallback_cmyk_tl, \c_@@_fallback_gray_tl, \c_@@_fallback_rgb_tl} -% Conversion from Separation or DeviceN spaces may not be possible; have -% a fallback to black. +% For every colorspace, we define one of the base colorspaces as a fallback. +% The base colorspaces themselves are their own fallback. % \begin{macrocode} -\tl_const:Nn \c_@@_fallback_cmyk_tl { 0 ~ 0 ~ 0 ~ 1 } -\tl_const:Nn \c_@@_fallback_gray_tl { 1 } -\tl_const:Nn \c_@@_fallback_rgb_tl { 1 ~ 1 ~ 1 } +\tl_const:Nn \c_@@_fallback_cmyk_tl { cmyk } +\tl_const:Nn \c_@@_fallback_gray_tl { gray } +\tl_const:Nn \c_@@_fallback_rgb_tl { rgb } % \end{macrocode} % \end{variable} % @@ -1803,14 +1841,13 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_model_init:nn} +% \begin{macro}{\@@_model_init:nnnn, \@@_model_init:nnnx} % A shared auxiliary to do the basics of setting up a new model: reserve a -% number, create a fallback and white-equivalent, set up links to the backend. +% number, create a white-equivalent, set up links to the backend. % \begin{macrocode} -\cs_new_protected:Npn \@@_model_init:nnnnn #1#2#3#4#5 +\cs_new_protected:Npn \@@_model_init:nnnn #1#2#3#4 { \int_gincr:N \g_@@_model_int - \tl_const:cn { c_@@_fallback_ #1 _tl } { #4 } \clist_map_inline:nn { fill , stroke , select } { \cs_new_protected:cpx { @@_backend_ ##1 _ #1 :n } ####1 @@ -1822,23 +1859,13 @@ \cs_new_protected:cpx { @@_model_ #1 _white: } { \prop_put:Nnn \exp_not:N \l_@@_named_white_prop {#1} - { \exp_not:n {#5} } + { \exp_not:n {#4} } \exp_not:N \int_compare:nNnF { \tex_currentgrouplevel:D } = 0 { \group_insert_after:N \exp_not:c { @@_model_ #1 _ white: } } } \use:c { @@_model_ #1 _white: } } -\cs_generate_variant:Nn \@@_model_init:nnnnn { nnnxx } -\cs_new_protected:Npn \@@_model_init:nnn #1#2#3 - { - \@@_model_init:nnnxx { #1 } { #2 } { #3 } - { - 1 \prg_replicate:nn { #2 - 1 } { ~ 1 } - } - { - 0 \prg_replicate:nn { #2 - 1 } { ~ 0 } - } - } +\cs_generate_variant:Nn \@@_model_init:nnnn { nnnx } % \end{macrocode} % \end{macro} % @@ -1921,7 +1948,7 @@ \cs_new_protected:Npn \@@_model_separation:w #1 , #2 , #3 , #4 , #5 \s_@@_stop #6#7#8 { - \@@_model_init:nnn {#6} { 1 } { separation } + \@@_model_init:nnnn {#6} { 1 } { separation } { 0 } \cs_new_eq:cN { @@_parse_mix_ #6 :nw } \@@_parse_mix_gray:nw \cs_new:cpn { @@_parse_model_ #6 :w } ##1 , ##2 \s_@@_stop { {#6} { \@@_parse_number:n {##1} } } @@ -1933,6 +1960,7 @@ } \cs_new_protected:Npn \@@_model_separation_cmyk:nnnnnn #1#2#3#4#5#6 { + \tl_const:cn { c_@@_fallback_ #1 _tl } { cmyk } \cs_new:cpn { @@_convert_ #1 _cmyk:w } ##1 \s_@@_stop { \fp_eval:n {##1 * #3} ~ @@ -1940,43 +1968,31 @@ \fp_eval:n {##1 * #5} ~ \fp_eval:n {##1 * #6} } - \@@_model_convert:nnn {#1} { cmyk } { rgb } - \@@_model_convert:nnn {#1} { cmyk } { gray } + \cs_new:cpn { @@_convert_cmyk_ #1 :w } ##1 \s_@@_stop { 1 } \prop_gput:Nnn \g_@@_alternative_values_prop {#1} { #3 , #4 , #5 , #6 } \@@_backend_separation_init:nnnnn {#2} { /DeviceCMYK } { } { 0 ~ 0 ~ 0 ~ 0 } { #3 ~ #4 ~ #5 ~ #6 } } \cs_new_protected:Npn \@@_model_separation_rgb:nnnnnn #1#2#3#4#5#6 { + \tl_const:cn { c_@@_fallback_ #1 _tl } { rgb } \cs_new:cpn { @@_convert_ #1 _rgb:w } ##1 \s_@@_stop { \fp_eval:n {##1 * #3} ~ \fp_eval:n {##1 * #4} ~ \fp_eval:n {##1 * #5} } - \@@_model_convert:nnn {#1} { rgb } { cmyk } - \@@_model_convert:nnn {#1} { rgb } { gray } + \cs_new:cpn { @@_convert_rgb_ #1 :w } ##1 \s_@@_stop { 1 } \prop_gput:Nnn \g_@@_alternative_values_prop {#1} { #3 , #4 , #5 } \@@_backend_separation_init:nnnnn {#2} { /DeviceRGB } { } { 0 ~ 0 ~ 0 } { #3 ~ #4 ~ #5 } } \cs_new_protected:Npn \@@_model_separation_gray:nnnnnn #1#2#3#4#5#6 { - \cs_new:cpn { @@_convert_ #1 _cmyk:w } ##1 \s_@@_stop - { - \fp_eval:n {##1 * #3} ~ - \fp_eval:n {##1 * #3} ~ - \fp_eval:n {##1 * #3} ~ - \fp_eval:n {##1 * #3} - } + \tl_const:cn { c_@@_fallback_ #1 _tl } { gray } \cs_new:cpn { @@_convert_ #1 _gray:w } ##1 \s_@@_stop { \fp_eval:n {##1 * #3} } - \cs_new:cpn { @@_convert_ #1 _rgb:w } ##1 \s_@@_stop - { - \fp_eval:n {##1 * #3} ~ - \fp_eval:n {##1 * #3} ~ - \fp_eval:n {##1 * #3} - } + \cs_new:cpn { @@_convert_gray_ #1 :w } ##1 \s_@@_stop { 1 } \prop_gput:Nnn \g_@@_alternative_values_prop {#1} {#3} \@@_backend_separation_init:nnnnn {#2} { /DeviceGray } { } { 0 } {#3} } @@ -2013,19 +2029,18 @@ % If a CIELAB space is being set up, we need the illuminant, then create % the appropriate set up. At present, this doesn't include \texttt{BlackPoint} % or \texttt{Range} data, but that may be added later. As CIELAB colors -% cannot be converted to anything else, we fallback to producing black: the -% user should set up a second model for colors set up this way. +% cannot be converted to anything else, we fallback to producing black in the +% gray colorspace: the user should set up a second model for colors set up this way. % \begin{macrocode} \cs_new_protected:Npn \@@_model_separation_CIELAB:nnnnnnn #1#2#3#4#5#6#7 { \tl_if_exist:cTF { c_@@_model_whitepoint_CIELAB_ #1 _tl } { \@@_backend_separation_init_CIELAB:nnn {#1} {#3} { #4 ~ #5 ~ #6 } - \cs_new:cpn { @@_convert_ #2 _cmyk:w } ##1 \s_@@_stop - { 0 ~ 0 ~ 0 ~ 1 } - \cs_new:cpn { @@_convert_ #2 _rgb:w } ##1 \s_@@_stop - { 1 ~ 1 ~ 1 } + \tl_const:cn { c_@@_fallback_ #2 _tl } { gray } \cs_new:cpn { @@_convert_ #2 _gray:w } ##1 \s_@@_stop + { 0 } + \cs_new:cpn { @@_convert_gray_ #2 :w } ##1 \s_@@_stop { 1 } } { @@ -2162,12 +2177,18 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_model_devicen:nnnn #1#2#3#4 { - \@@_model_init:nnn {#4} {#1} { devicen } + \@@_model_init:nnnx {#4} {#1} { devicen } + { + 0 \prg_replicate:nn { #1 - 1 } { ~ 0 } + } \cs_if_exist_use:cF { @@_model_devicen_parse_ #1 :nn } { \@@_model_devicen_parse_generic:nn } {#4} {#1} \@@_model_devicen_init:nnn {#1} {#2} {#3} - \@@_model_devicen_convert:nnn {#4} {#2} {#3} + \@@_model_devicen_convert:nnnx {#4} {#2} {#3} + { + 1 \prg_replicate:nn { #1 - 1 } { ~ 1 } + } } % \end{macrocode} % For short lists of DeviceN colors, we can use hand-tuned parsing. This @@ -2382,30 +2403,29 @@ % to other parameter-based spaces. Essentially the approach is exactly the same % as the PostScript, just expressed in \TeX{} terms. % \begin{macrocode} -\cs_new_protected:Npn \@@_model_devicen_convert:nnn #1#2#3 +\cs_new_protected:Npn \@@_model_devicen_convert:nnnn #1#2#3 { - \use:c { @@_model_devicen_convert_ #2 :nn } {#1} {#3} + \use:c { @@_model_devicen_convert_ #2 :nnn } {#1} {#3} } -\cs_new_protected:Npn \@@_model_devicen_convert_cmyk:nn #1#2 +\cs_generate_variant:Nn \@@_model_devicen_convert:nnnn { nnnx } +\cs_new_protected:Npn \@@_model_devicen_convert_cmyk:nnn #1#2 { - \@@_model_convert:nnn {#1} { cmyk } { gray } - \@@_model_convert:nnn {#1} { cmyk } { rgb } - \@@_model_devicen_convert:nnnn {#1} { cmyk } { 4 } {#2} + \tl_const:cn { c_@@_fallback_ #1 _tl } { cmyk } + \@@_model_devicen_convert:nnnnn {#1} { cmyk } { 4 } {#2} } -\cs_new_protected:Npn \@@_model_devicen_convert_gray:nn #1#2 +\cs_new_protected:Npn \@@_model_devicen_convert_gray:nnn #1#2 { - \@@_model_convert:nnn {#1} { gray } { cmyk } - \@@_model_convert:nnn {#1} { gray } { rgb } - \@@_model_devicen_convert:nnnn {#1} { gray } { 1 } {#2} + \tl_const:cn { c_@@_fallback_ #1 _tl } { gray } + \@@_model_devicen_convert:nnnnn {#1} { gray } { 1 } {#2} } -\cs_new_protected:Npn \@@_model_devicen_convert_rgb:nn #1#2 +\cs_new_protected:Npn \@@_model_devicen_convert_rgb:nnn #1#2 { - \@@_model_convert:nnn {#1} { rgb } { cmyk } - \@@_model_convert:nnn {#1} { rgb } { gray } - \@@_model_devicen_convert:nnnn {#1} { rgb } { 3 } {#2} + \tl_const:cn { c_@@_fallback_ #1 _tl } { rgb } + \@@_model_devicen_convert:nnnnn {#1} { rgb } { 3 } {#2} } -\cs_new_protected:Npn \@@_model_devicen_convert:nnnn #1#2#3#4 +\cs_new_protected:Npn \@@_model_devicen_convert:nnnnn #1#2#3#4#5 { + \cs_new:cpn { @@_convert_ #2 _ #1 :w } ##1 \s_@@_stop {#5} \cs_new:cpx { @@_convert_ #1 _ #2 :w } ##1 \s_@@_stop { \exp_not:c { @@_convert_devicen_ #2 : \prg_replicate:nn {#3} { n } w } @@ -2607,7 +2627,10 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_model_iccbased_aux:nnnnnn #1#2#3#4#5#6 { - \@@_model_init:nnnnn {#5} {#1} { iccbased } {#2} {#3} + \@@_model_init:nnnn {#5} {#1} { iccbased } {#3} + \tl_const:cn { c_@@_fallback_ #5 _tl } { gray } + \cs_new:cpn { @@_convert_ #5 _gray:w } ##1 \s_@@_stop { 0 } + \cs_new:cpn { @@_convert_gray_ #5 :w } ##1 \s_@@_stop { #2 } \use:c { @@_model_devicen_parse_ #1 :nn } {#5} {#1} \exp_args:Nx \@@_backend_iccbased_init:nnn { \file_full_name:n {#6} } {#1} {#4} |