aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMark Oteiza2017-09-13 10:27:37 -0400
committerMark Oteiza2017-09-13 10:27:37 -0400
commit5d4c539bd7e15e7fd0fb092276791b6287260a9a (patch)
treecc46c19ff16d9f12a6f6f8c2e2f5ba5807654c31 /src
parent9a8bbb9d5d3a55d4a31658e188f305669bd26e79 (diff)
downloademacs-5d4c539bd7e15e7fd0fb092276791b6287260a9a.tar.gz
emacs-5d4c539bd7e15e7fd0fb092276791b6287260a9a.zip
Add lcms2 interface
configure.ac: Add boilerplate for configuring and detecting liblcms2. etc/NEWS: Mention new configure option and color-distance change. src/Makefile.in: Add references to lcms.c and liblcms. src/emacs.c: Define lcms2 symbols. src/lcms.c: New file. src/lisp.h: Add declaration for lcms2. src/xfaces.c: Add optional METRIC argument.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in6
-rw-r--r--src/emacs.c4
-rw-r--r--src/lcms.c182
-rw-r--r--src/lisp.h5
-rw-r--r--src/xfaces.c15
5 files changed, 205 insertions, 7 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index dde3f1d3fb4..a98ad9c5ebd 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -234,6 +234,8 @@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
234 234
235GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@ 235GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@
236 236
237LIBLCMS2 = @LIBLCMS2@
238
237LIBZ = @LIBZ@ 239LIBZ = @LIBZ@
238 240
239## system-specific libs for dynamic modules, else empty 241## system-specific libs for dynamic modules, else empty
@@ -389,7 +391,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
389 syntax.o $(UNEXEC_OBJ) bytecode.o \ 391 syntax.o $(UNEXEC_OBJ) bytecode.o \
390 process.o gnutls.o callproc.o \ 392 process.o gnutls.o callproc.o \
391 region-cache.o sound.o atimer.o \ 393 region-cache.o sound.o atimer.o \
392 doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \ 394 doprnt.o intervals.o textprop.o composite.o xml.o lcms.o $(NOTIFY_OBJ) \
393 $(XWIDGETS_OBJ) \ 395 $(XWIDGETS_OBJ) \
394 profiler.o decompress.o \ 396 profiler.o decompress.o \
395 thread.o systhread.o \ 397 thread.o systhread.o \
@@ -490,7 +492,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
490 $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \ 492 $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
491 $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ 493 $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
492 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ 494 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
493 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) \ 495 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LIBLCMS2) \
494 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) 496 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS)
495 497
496## FORCE it so that admin/unidata can decide whether these files 498## FORCE it so that admin/unidata can decide whether these files
diff --git a/src/emacs.c b/src/emacs.c
index 44f6285795a..668711a5ab9 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1546,6 +1546,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1546 syms_of_xml (); 1546 syms_of_xml ();
1547#endif 1547#endif
1548 1548
1549#ifdef HAVE_LCMS2
1550 syms_of_lcms2 ();
1551#endif
1552
1549#ifdef HAVE_ZLIB 1553#ifdef HAVE_ZLIB
1550 syms_of_decompress (); 1554 syms_of_decompress ();
1551#endif 1555#endif
diff --git a/src/lcms.c b/src/lcms.c
new file mode 100644
index 00000000000..120ef769810
--- /dev/null
+++ b/src/lcms.c
@@ -0,0 +1,182 @@
1/* Interface to Little CMS
2 Copyright (C) 2017 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#ifdef HAVE_LCMS2
22
23#include <lcms2.h>
24#include <math.h>
25
26#include "lisp.h"
27
28static bool
29parse_lab_list (Lisp_Object lab_list, cmsCIELab *color)
30{
31#define PARSE_LAB_LIST_FIELD(field) \
32 if (CONSP (lab_list) && NUMBERP (XCAR (lab_list))) \
33 { \
34 color->field = XFLOATINT (XCAR (lab_list)); \
35 lab_list = XCDR (lab_list); \
36 } \
37 else \
38 return false;
39
40 PARSE_LAB_LIST_FIELD (L);
41 PARSE_LAB_LIST_FIELD (a);
42 PARSE_LAB_LIST_FIELD (b);
43
44 return true;
45}
46
47/* http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf> */
48
49DEFUN ("lcms-cie-de2000", Flcms_cie_de2000, Slcms_cie_de2000, 2, 5, 0,
50 doc: /* Compute CIEDE2000 metric distance between COLOR1 and COLOR2.
51Each color is a list of L*a*b* coordinates, where the L* channel ranges from
520 to 100, and the a* and b* channels range from -128 to 128.
53Optional arguments KL, KC, KH are weighting parameters for lightness,
54chroma, and hue, respectively. The parameters each default to 1. */)
55 (Lisp_Object color1, Lisp_Object color2,
56 Lisp_Object kL, Lisp_Object kC, Lisp_Object kH)
57{
58 cmsCIELab Lab1, Lab2;
59 cmsFloat64Number Kl, Kc, Kh;
60
61 if (!(CONSP (color1) && parse_lab_list (color1, &Lab1)))
62 signal_error ("Invalid color", color1);
63 if (!(CONSP (color2) && parse_lab_list (color2, &Lab2)))
64 signal_error ("Invalid color", color1);
65 if (NILP (kL))
66 Kl = 1.0f;
67 else if (!(NUMBERP (kL) && (Kl = XFLOATINT(kL))))
68 wrong_type_argument(Qnumberp, kL);
69 if (NILP (kC))
70 Kc = 1.0f;
71 else if (!(NUMBERP (kC) && (Kc = XFLOATINT(kC))))
72 wrong_type_argument(Qnumberp, kC);
73 if (NILP (kL))
74 Kh = 1.0f;
75 else if (!(NUMBERP (kH) && (Kh = XFLOATINT(kH))))
76 wrong_type_argument(Qnumberp, kH);
77
78 return make_float (cmsCIE2000DeltaE (&Lab1, &Lab2, Kl, Kc, Kh));
79}
80
81/* FIXME: code duplication */
82
83static bool
84parse_xyz_list (Lisp_Object xyz_list, cmsCIEXYZ *color)
85{
86#define PARSE_XYZ_LIST_FIELD(field) \
87 if (CONSP (xyz_list) && NUMBERP (XCAR (xyz_list))) \
88 { \
89 color->field = 100.0 * XFLOATINT (XCAR (xyz_list)); \
90 xyz_list = XCDR (xyz_list); \
91 } \
92 else \
93 return false;
94
95 PARSE_XYZ_LIST_FIELD (X);
96 PARSE_XYZ_LIST_FIELD (Y);
97 PARSE_XYZ_LIST_FIELD (Z);
98
99 return true;
100}
101
102DEFUN ("lcms-cam02-ucs", Flcms_cam02_ucs, Slcms_cam02_ucs, 2, 3, 0,
103 doc: /* Compute CAM02-UCS metric distance between COLOR1 and COLOR2.
104Each color is a list of XYZ coordinates, with Y scaled to unity.
105Optional argument is the XYZ white point, which defaults to illuminant D65. */)
106 (Lisp_Object color1, Lisp_Object color2, Lisp_Object whitepoint)
107{
108 cmsViewingConditions vc;
109 cmsJCh jch1, jch2;
110 cmsHANDLE h1, h2;
111 cmsCIEXYZ xyz1, xyz2, xyzw;
112 double Jp1, ap1, bp1, Jp2, ap2, bp2;
113 double Mp1, Mp2, FL, k, k4;
114
115 if (!(CONSP (color1) && parse_xyz_list (color1, &xyz1)))
116 signal_error ("Invalid color", color1);
117 if (!(CONSP (color2) && parse_xyz_list (color2, &xyz2)))
118 signal_error ("Invalid color", color1);
119 if (NILP (whitepoint))
120 {
121 xyzw.X = 95.047;
122 xyzw.Y = 100.0;
123 xyzw.Z = 108.883;
124 }
125 else if (!(CONSP (whitepoint) && parse_xyz_list(whitepoint, &xyzw)))
126 signal_error("Invalid white point", whitepoint);
127
128 vc.whitePoint.X = xyzw.X;
129 vc.whitePoint.Y = xyzw.Y;
130 vc.whitePoint.Z = xyzw.Z;
131 vc.Yb = 20;
132 vc.La = 100;
133 vc.surround = AVG_SURROUND;
134 vc.D_value = 1.0;
135
136 h1 = cmsCIECAM02Init (0, &vc);
137 h2 = cmsCIECAM02Init (0, &vc);
138 cmsCIECAM02Forward (h1, &xyz1, &jch1);
139 cmsCIECAM02Forward (h2, &xyz2, &jch2);
140 cmsCIECAM02Done (h1);
141 cmsCIECAM02Done (h2);
142
143 /* Now have colors in JCh, need to calculate J'a'b'
144
145 M = C * F_L^0.25
146 J' = 1.7 J / (1 + 0.007 J)
147 M' = 43.86 ln(1 + 0.0228 M)
148 a' = M' cos(h)
149 b' = M' sin(h)
150
151 where
152
153 F_L = 0.2 k^4 (5 L_A) + 0.1 (1 - k^4)^2 (5 L_A)^(1/3),
154 k = 1/(5 L_A + 1)
155 */
156 k = 1.0 / (1.0 + (5.0 * vc.La));
157 k4 = k * k * k * k;
158 FL = vc.La * k4 + 0.1 * (1 - k4) * (1 - k4) * cbrt (5.0 * vc.La);
159 Mp1 = 43.86 * log (1.0 + 0.0228 * (jch1.C * sqrt (sqrt (FL))));
160 Mp2 = 43.86 * log (1.0 + 0.0228 * (jch2.C * sqrt (sqrt (FL))));
161 Jp1 = 1.7 * jch1.J / (1.0 + (0.007 * jch1.J));
162 Jp2 = 1.7 * jch2.J / (1.0 + (0.007 * jch2.J));
163 ap1 = Mp1 * cos (jch1.h);
164 ap2 = Mp2 * cos (jch2.h);
165 bp1 = Mp1 * sin (jch1.h);
166 bp2 = Mp2 * sin (jch2.h);
167
168 return make_float (sqrt ((Jp2 - Jp1) * (Jp2 - Jp1) +
169 (ap2 - ap1) * (ap2 - ap1) +
170 (bp2 - bp1) * (bp2 - bp1)));
171}
172
173
174/* Initialization */
175void
176syms_of_lcms2 (void)
177{
178 defsubr (&Slcms_cie_de2000);
179 defsubr (&Slcms_cam02_ucs);
180}
181
182#endif /* HAVE_LCMS2 */
diff --git a/src/lisp.h b/src/lisp.h
index 81f8d6a24b5..19594e7830d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4396,6 +4396,11 @@ extern void syms_of_xml (void);
4396extern void xml_cleanup_parser (void); 4396extern void xml_cleanup_parser (void);
4397#endif 4397#endif
4398 4398
4399#ifdef HAVE_LCMS2
4400/* Defined in lcms.c. */
4401extern void syms_of_lcms2 (void);
4402#endif
4403
4399#ifdef HAVE_ZLIB 4404#ifdef HAVE_ZLIB
4400/* Defined in decompress.c. */ 4405/* Defined in decompress.c. */
4401extern void syms_of_decompress (void); 4406extern void syms_of_decompress (void);
diff --git a/src/xfaces.c b/src/xfaces.c
index 86bb9b0b496..32a5bd5f60b 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -4088,12 +4088,14 @@ color_distance (XColor *x, XColor *y)
4088} 4088}
4089 4089
4090 4090
4091DEFUN ("color-distance", Fcolor_distance, Scolor_distance, 2, 3, 0, 4091DEFUN ("color-distance", Fcolor_distance, Scolor_distance, 2, 4, 0,
4092 doc: /* Return an integer distance between COLOR1 and COLOR2 on FRAME. 4092 doc: /* Return an integer distance between COLOR1 and COLOR2 on FRAME.
4093COLOR1 and COLOR2 may be either strings containing the color name, 4093COLOR1 and COLOR2 may be either strings containing the color name,
4094or lists of the form (RED GREEN BLUE). 4094or lists of the form (RED GREEN BLUE), each in the range 0 to 65535 inclusive.
4095If FRAME is unspecified or nil, the current frame is used. */) 4095If FRAME is unspecified or nil, the current frame is used.
4096 (Lisp_Object color1, Lisp_Object color2, Lisp_Object frame) 4096If METRIC is unspecified or nil, a modified L*u*v* metric is used. */)
4097 (Lisp_Object color1, Lisp_Object color2, Lisp_Object frame,
4098 Lisp_Object metric)
4097{ 4099{
4098 struct frame *f = decode_live_frame (frame); 4100 struct frame *f = decode_live_frame (frame);
4099 XColor cdef1, cdef2; 4101 XColor cdef1, cdef2;
@@ -4107,7 +4109,10 @@ If FRAME is unspecified or nil, the current frame is used. */)
4107 && defined_color (f, SSDATA (color2), &cdef2, false))) 4109 && defined_color (f, SSDATA (color2), &cdef2, false)))
4108 signal_error ("Invalid color", color2); 4110 signal_error ("Invalid color", color2);
4109 4111
4110 return make_number (color_distance (&cdef1, &cdef2)); 4112 if (NILP (metric))
4113 return make_number (color_distance (&cdef1, &cdef2));
4114 else
4115 return call2 (metric, color1, color2);
4111} 4116}
4112 4117
4113 4118