[latex3-commits] [git/LaTeX3-latex3-latex3] color-models: Add support for CIE-Lab colors (280de807a)

Joseph Wright joseph.wright at morningstar2.co.uk
Thu Jul 16 20:19:41 CEST 2020


Repository : https://github.com/latex3/latex3
On branch  : color-models
Link       : https://github.com/latex3/latex3/commit/280de807a05b2a6358f2796ace4e0d9b0965217c

>---------------------------------------------------------------

commit 280de807a05b2a6358f2796ace4e0d9b0965217c
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date:   Thu Jul 16 18:50:30 2020 +0100

    Add support for CIE-Lab colors


>---------------------------------------------------------------

280de807a05b2a6358f2796ace4e0d9b0965217c
 l3experimental/l3color/l3color.dtx              | 162 ++++++++++++++++++++++--
 l3experimental/l3color/testfiles/m3color003.lvt |  12 ++
 l3experimental/l3color/testfiles/m3color003.tlg |  28 ++++
 3 files changed, 193 insertions(+), 9 deletions(-)

diff --git a/l3experimental/l3color/l3color.dtx b/l3experimental/l3color/l3color.dtx
index 58b46bd03..19bac84bb 100644
--- a/l3experimental/l3color/l3color.dtx
+++ b/l3experimental/l3color/l3color.dtx
@@ -334,12 +334,28 @@
 %     name of a spot color ink. Such a \meta{name} may contain spaces, etc.,
 %     which are not permitted in the \meta{model}.
 %   \item \texttt{alternative-model} An alternative device colorspace, one of
-%     \texttt{cmyk}, \texttt{rgb} or \texttt{gray}
+%     \texttt{cmyk}, \texttt{rgb}, \texttt{gray} or \texttt{CIELAB}. The three
+%     parameter-based models work as described above; see below for
+%     details of CIELAB colors.
 %   \item \texttt{alternative-values} A comma-separated list of values
 %     appropriate to the \texttt{alternative-model}. This information is used by
 %     the PDF application if the \texttt{Separation} is not available.
 % \end{itemize}
 %
+% CIELAB color separations are created using the
+% \texttt{alternative-model = CIELAB} setting. These colors must also have an
+% \texttt{illuminant} key, one of \texttt{a}, \texttt{c}, \texttt{e},
+% \texttt{d50}, \texttt{d55}, \texttt{d65} or \texttt{d75}. The
+% \texttt{alternative-values} in this case are the three parameters $L$, $a$
+% and $b$ of the CIELAB model. Full details of this device-independent color
+% approach are given in the documentation to the \pkg{colorspace} package.
+%
+% CIELAB colors \emph{cannot} be converted into other device-dependent color
+% spaces, and as such, mixing can only occur if colors set up using the CIELAB
+% model are also given with an alternative parameter-based model. If that is
+% not the case, \pkg{l3color} will fallback to using black as the colorant in
+% any mixing.
+%
 % \end{documentation}
 %
 % \begin{implementation}
@@ -1331,6 +1347,35 @@
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{variable}
+%   {
+%     \c_@@_model_whitepoint_CIELAB_a_tl   ,
+%     \c_@@_model_whitepoint_CIELAB_b_tl   ,
+%     \c_@@_model_whitepoint_CIELAB_e_tl   ,
+%     \c_@@_model_whitepoint_CIELAB_d50_tl ,
+%     \c_@@_model_whitepoint_CIELAB_d55_tl ,
+%     \c_@@_model_whitepoint_CIELAB_d65_tl ,
+%     \c_@@_model_whitepoint_CIELAB_d75_tl
+%   }
+%   Whitepoint data for the CIELAB profiles. 
+%    \begin{macrocode}
+\tl_const:Nn \c_@@_model_whitepoint_CIELAB_a_tl      { 1.0985 ~ 1 ~ 0.3558 }
+\tl_const:Nn \c_@@_model_whitepoint_CIELAB_b_tl      { 0.9807~ 1 ~ 1.1822 }
+\tl_const:Nn \c_@@_model_whitepoint_CIELAB_e_tl      { 1 ~ 1 ~ 1 }
+\tl_const:cn { c_@@_model_whitepoint_CIELAB_d50_tl } { 0.9642 ~, 1 ~ 0.8251 }
+\tl_const:cn { c_@@_model_whitepoint_CIELAB_d55_tl } { 0.9568 ~ 1 ~ 0.9214 }
+\tl_const:cn { c_@@_model_whitepoint_CIELAB_d65_tl } { 0.9504 ~ 1 ~ 1.0888 }
+\tl_const:cn { c_@@_model_whitepoint_CIELAB_d75_tl } { 0.9497 ~ 1 ~ 1.2261 }
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_model_range_CIELAB_tl}
+%   The range for CIELAB color spaces.
+%    \begin{macrocode}
+\tl_const:Nn \c_@@_model_range_CIELAB_tl { -128 ~ 127 ~ -128 ~ 127 }
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{macro}{\color_model_new:nnn, \@@_model_new:nnn}
 % \begin{macro}{\@@_model_separation:n}
 % \begin{macro}{\@@_model_separation:nn}
@@ -1342,8 +1387,12 @@
 %     \@@_model_separation_gray:nnnnnn ,
 %     \@@_model_separation_rgb:nnnnnn
 %   }
-% \begin{macro}{\@@_model_conver:nnn}
-% \begin{macro}{\@@_model_separation_init:nnnn}
+% \begin{macro}{\@@_model_convert:nnn}
+% \begin{macro}{\@@_model_separation_CIELAB:nnnnnn}
+% \begin{macro}{\@@_model_separation_CIELAB:nnnnnnn}
+% \begin{macro}{\@@_model_separation_init:nnnnn}
+% \begin{macro}{\@@_model_separation_init_CIELAB:n}
+% \begin{macro}{\@@_model_separation_init_CIELAB:nnnnn}
 %   Set up a new model: in general this has to be handled by a family-dependent
 %   function. To avoid some \enquote{interesting} questions with casing, we
 %   fold the case of the family name. The key--value list should always be
@@ -1471,7 +1520,7 @@
       }
     \@@_model_convert:nnn {#1} { cmyk } { rgb }
     \@@_model_convert:nnn {#1} { cmyk } { gray }
-    \@@_model_separation_init:nnnn {#2} { /DeviceCMYK }
+    \@@_model_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
@@ -1484,7 +1533,7 @@
       }
     \@@_model_convert:nnn {#1} { rgb } { cmyk }
     \@@_model_convert:nnn {#1} { rgb } { gray }
-    \@@_model_separation_init:nnnn {#2} { /DeviceRGB }
+    \@@_model_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
@@ -1504,7 +1553,7 @@
         \fp_eval:n {##1 * #3} ~
         \fp_eval:n {##1 * #3}
       }
-    \@@_model_separation_init:nnnn {#2} { /DeviceGray } { 0 } {#3}
+    \@@_model_separation_init:nnnnn {#2} { /DeviceGray } { } { 0 } {#3}
   }
 %    \end{macrocode}
 %   Generic model conversion \emph{via} an alternative intermediate.
@@ -1520,17 +1569,64 @@
       }
   }
 %    \end{macrocode}
+%   Setting up for CIELAB needs a bit more work: there is the illuminant and
+%   the need for an appropriate object.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_model_separation_CIELAB:nnnnnn #1#2#3#4#5#6
+  {
+    \prop_get:NnNF \l_@@_internal_prop { illuminant }
+      \l_@@_internal_tl
+      {
+        \__kernel_msg_error:nnn { color }
+          { CIELAB-requires-illuminant } {#1}
+        \tl_set:Nn \l_@@_internal_tl { d50 }
+      }
+    \exp_args:NV \@@_model_separation_CIELAB:nnnnnnn
+      \l_@@_internal_tl {#1} {#2} {#3} {#4} {#5} {#6}
+  }
+%    \end{macrocode}
+%   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.
+%    \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 }
+      {
+        \@@_model_separation_init_CIELAB:n {#1}
+        \@@_model_separation_init_CIELAB:nnnnn {#2} {#3} {#4} {#5} {#6}
+        \cs_new:cpn { @@_convert_ #1 _cmyk:w } ##1 ~ ##2 \s_@@_stop
+          { 0 ~ 0 ~ 0 ~ 1 }
+        \cs_new:cpn { @@_convert_ #1 _rgb:w } ##1 ~ ##2 \s_@@_stop
+          { 1 ~ 1 ~ 1 }
+        \cs_new:cpn { @@_convert_ #1 _gray:w } ##1 ~ ##2 \s_@@_stop
+          { 1 }
+      }
+      {
+        \__kernel_msg_error:nnn { color }
+          { unknown-CIELAB-illuminant } {#1}
+      }
+  }
+%    \end{macrocode}
 %   Initialising the PDF structures needs two parts: creating an object
 %   containing the \enquote{real} name of the Separation, then adding a reference
 %   to that to each page. The latter uses the internal name of the \texttt{cs}.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_model_separation_init:nnnn #1#2#3#4
+\cs_new_protected:Npn \@@_model_separation_init:nnnnn #1#2#3#4#5
   {
     \pdf_object_now:nx { array }
       {
         /Separation
         / \str_convert_pdfname:n {#1} ~ #2 ~
-        << /FunctionType ~ 2 /Domain ~ [0 ~ 1] /C0 ~ [#3] ~ /C1 ~ [#4] /N ~ 1 >>
+        <<
+          /FunctionType ~ 2
+          /Domain ~ [0 ~ 1]
+          \tl_if_blank:nF {#3} { /Range ~ [#3] }
+          /C0 ~ [#4] ~
+          /C1 ~ [#5] /N ~ 1
+        >>
       }
     \use:x
       {
@@ -1541,7 +1637,35 @@
       }
   }
 \cs_if_exist:NF \pdf_object_now:nn
-  { \cs_gset_protected:Npn \@@_model_separation_init:nnnn #1#2#3#4 { } }
+  { \cs_gset_protected:Npn \@@_model_separation_init:nnnnn #1#2#3#4#5 { } }
+%    \end{macrocode}
+%   For CIELAB colors, we need one object per document for the illuminant,
+%   plus initialisation of the color space referencing that object.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_model_separation_init_CIELAB:n #1
+  {
+    \pdf_object_new:nn { @@_illuminant_CIELAB_ #1 } { array }
+    \pdf_object_write:nx { @@_illuminant_CIELAB_ #1 }
+      {
+        /Lab ~
+        <<
+         /WhitePoint ~
+           [ \tl_use:c { c_@@_model_whitepoint_CIELAB_ #1 _tl } ]
+         /Range ~ [ \c_@@_model_range_lab_tl ]
+        >>
+     }
+  }
+\cs_if_exist:NF \pdf_object_new:nn
+  { \cs_gset_protected:Npn \@@_model_separation_init_CIELAB:n #1 { } }
+\cs_new_protected:Npn \@@_model_separation_init_CIELAB:nnnnn #1#2#3#4#5
+  {
+    \@@_model_separation_init:nnnnn
+      {#2}
+      { \pdf_object_ref:n { @@_illuminant_CIELAB_ #1 } }
+      { \c_@@_model_range_lab_tl }
+      { 100 ~ 0 ~ 0 }
+      { #3 ~ #4 ~ #5 }
+  }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1551,6 +1675,10 @@
 % \end{macro}
 % \end{macro}
 % \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
 %
 % \subsection{Diagnostics}
 %
@@ -1586,6 +1714,16 @@
 % \subsection{Messages}
 %
 % \begin{macrocode}
+\__kernel_msg_new:nnnn { color } { CIELAB-requires-illuminant }
+  { CIELAB~color~space~'#1'~require~an~illuminant. }
+  {
+    LaTeX~has~been~asked~to~create~a~separation~color~space~using~
+    CIELAB~specifications,~but~no~\\ \\
+    \iow_indent:n { illuminant = <basis> }
+    \\ \\
+    key~was~given~with~the~correct~information.~LaTeX~will~use~illuminant~
+    'd50'~for~recovery.
+  }
 \__kernel_msg_new:nnnn { color } { conversion-not-available }
   { No~model~conversion~available~from~'#1'~to~'#2'. }
   {
@@ -1646,6 +1784,12 @@
     LaTeX~has~been~asked~to~export~a~color~in~format~'#1',~
     but~this~has~never~been~defined.
   }
+\__kernel_msg_new:nnnn { color } { unknown-CIELAB-illuminant }
+  { Unknown~illuminant~model~'#1'. }
+  {
+    LaTeX~has~been~asked~to~use~create~a~color~space~using~CIELAB~
+    illuminant~'#1',~but~this~does~not~exist.
+  }
 \__kernel_msg_new:nnnn { color } { unknown-model }
   { Unknown~color~model~'#1'. }
   {
diff --git a/l3experimental/l3color/testfiles/m3color003.lvt b/l3experimental/l3color/testfiles/m3color003.lvt
index 6977d9772..d5a6e3a54 100644
--- a/l3experimental/l3color/testfiles/m3color003.lvt
+++ b/l3experimental/l3color/testfiles/m3color003.lvt
@@ -161,6 +161,14 @@
     \test:nn { CMYK } { 0.1 , 0.2 , 0.3 , 0.4 }
     \test:nn { RGB  } { 0.1 , 0.2 , 0.3 }
     \test:nn { Gray } { 0.1 }
+    \color_model_new:nnn { BarToneLab } { Separation }
+      {
+        name = BarTone~555~GN ,
+        alternative-model = CIELAB ,
+        alternative-values = {50, -30, -40},
+        illuminant = d65
+      }
+    \color_show:n { BarToneLab }
   }
 
 \TEST { Creating~new~models:~errors }
@@ -174,6 +182,10 @@
       { name = BarTone~555~GN , alternative-model }
     \color_model_new:nnn { foo4 } { separation }
       { name = BarTone~555~GN , alternative-model = foo }
+    \color_model_new:nnn { foo5 } { separation }
+      { name = BarTone~555~GN , alternative-model = CIELAB }
+    \color_model_new:nnn { foo5 } { separation }
+      { name = BarTone~555~GN , alternative-model = CIELAB , illuminant = dave }
   }
 
 \TEST { Converting~new~models }
diff --git a/l3experimental/l3color/testfiles/m3color003.tlg b/l3experimental/l3color/testfiles/m3color003.tlg
index 99b060f8f..364c20658 100644
--- a/l3experimental/l3color/testfiles/m3color003.tlg
+++ b/l3experimental/l3color/testfiles/m3color003.tlg
@@ -229,6 +229,18 @@ The color fooGray has the properties:
 >  BarToneGray  =>  0.5.
 <recently read> }
 l. ...  }
+Defining \c__color_fallback_BarToneLab_tl on line ...
+Defining \__color_parse_mix_BarToneLab:nw on line ...
+Defining \__color_parse_model_BarToneLab:w on line ...
+Defining \__color_backend_BarToneLab:n on line ...
+Defining \__color_convert_d65_cmyk:w on line ...
+Defining \__color_convert_d65_rgb:w on line ...
+Defining \__color_convert_d65_gray:w on line ...
+Defining \__color_model_BarToneLab_white: on line ...
+The color BarToneLab is undefined.
+> .
+<recently read> }
+l. ...  }
 ============================================================
 ============================================================
 TEST 8: Creating new models: errors
@@ -282,6 +294,22 @@ LaTeX has been asked to create a separation color space, but the model given
 as
     alternative-model=<model>
 is unknown.
+! LaTeX3 Error: Separation color space 'foo5' require values for the
+(LaTeX3)        alternative space.
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+LaTeX has been asked to create a separation color space, but no 
+    alternative-values=<model>
+key was given with the correct information.
+! LaTeX3 Error: Separation color space 'foo5' require values for the
+(LaTeX3)        alternative space.
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+LaTeX has been asked to create a separation color space, but no 
+    alternative-values=<model>
+key was given with the correct information.
 ============================================================
 ============================================================
 TEST 9: Converting new models





More information about the latex3-commits mailing list.