diff --git a/configure.ac b/configure.ac
index 5aaf006c54..e85c1e4d97 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3151,7 +3151,7 @@ AC_DEFUN
OLD_LIBS="$LIBS"
CPPFLAGS="$CPPFLAGS $XFT_CFLAGS"
CFLAGS="$CFLAGS $XFT_CFLAGS"
- XFT_LIBS="-lXrender $XFT_LIBS"
+ XFT_LIBS="-lXrender $XFT_LIBS -llcms2"
LIBS="$XFT_LIBS $LIBS"
AC_CHECK_HEADER(X11/Xft/Xft.h,
AC_CHECK_LIB(Xft, XftFontOpen, HAVE_XFT=yes, , $XFT_LIBS) , ,
diff --git a/src/xfaces.c b/src/xfaces.c
index accb98bf4c..604404aafd 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -205,6 +205,8 @@ along with GNU Emacs. If not, see . */
#include
#include
+#include
+
#include "lisp.h"
#include "character.h"
#include "frame.h"
@@ -352,7 +354,7 @@ static struct face_cache *make_face_cache (struct frame *);
static void free_face_cache (struct face_cache *);
static bool merge_face_ref (struct frame *, Lisp_Object, Lisp_Object *,
bool, struct named_merge_point *);
-static int color_distance (XColor *x, XColor *y);
+static double color_distance (XColor *x, XColor *y);
#ifdef HAVE_WINDOW_SYSTEM
static void set_font_frame_param (Lisp_Object, Lisp_Object);
@@ -4063,35 +4065,41 @@ prepare_face_for_display (struct frame *f, struct face *face)
/* Returns the `distance' between the colors X and Y. */
-static int
+static double
color_distance (XColor *x, XColor *y)
{
- /* This formula is from a paper titled `Colour metric' by Thiadmer Riemersma.
- Quoting from that paper:
-
- This formula has results that are very close to L*u*v* (with the
- modified lightness curve) and, more importantly, it is a more even
- algorithm: it does not have a range of colors where it suddenly
- gives far from optimal results.
-
- See for more info. */
-
- long r = (x->red - y->red) >> 8;
- long g = (x->green - y->green) >> 8;
- long b = (x->blue - y->blue) >> 8;
- long r_mean = (x->red + y->red) >> 9;
-
- return
- (((512 + r_mean) * r * r) >> 8)
- + 4 * g * g
- + (((767 - r_mean) * b * b) >> 8);
+ /* http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf> */
+ cmsHPROFILE profile_in, profile_out;
+ cmsHTRANSFORM transform;
+ cmsCIELab Labx, Laby;
+ cmsUInt16Number rgbx[3], rgby[3];
+ cmsFloat64Number delta;
+
+ profile_in = cmsCreate_sRGBProfile();
+ profile_out = cmsCreateLab4Profile(NULL);
+ transform = cmsCreateTransform(profile_in, TYPE_RGB_16,
+ profile_out, TYPE_Lab_DBL,
+ INTENT_PERCEPTUAL, 0);
+ cmsCloseProfile(profile_in);
+ cmsCloseProfile(profile_out);
+ rgbx[0] = x->red;
+ rgbx[1] = x->green;
+ rgbx[2] = x->blue;
+ rgby[0] = y->red;
+ rgby[1] = y->green;
+ rgby[2] = y->blue;
+ cmsDoTransform(transform, rgbx, &Labx, 1);
+ cmsDoTransform(transform, rgby, &Laby, 1);
+ cmsDeleteTransform(transform);
+ delta = cmsCIE2000DeltaE(&Labx, &Laby, 1.0, 1.0, 1.0);
+ return delta;
}
DEFUN ("color-distance", Fcolor_distance, Scolor_distance, 2, 3, 0,
- doc: /* Return an integer distance between COLOR1 and COLOR2 on FRAME.
+ doc: /* Return a float distance between COLOR1 and COLOR2 on FRAME.
COLOR1 and COLOR2 may be either strings containing the color name,
-or lists of the form (RED GREEN BLUE).
+or lists of the form (RED GREEN BLUE), in the range 0 to 65355 inclusive.
If FRAME is unspecified or nil, the current frame is used. */)
(Lisp_Object color1, Lisp_Object color2, Lisp_Object frame)
{
@@ -4107,7 +4115,7 @@ If FRAME is unspecified or nil, the current frame is used. */)
&& defined_color (f, SSDATA (color2), &cdef2, false)))
signal_error ("Invalid color", color2);
- return make_number (color_distance (&cdef1, &cdef2));
+ return make_float (color_distance (&cdef1, &cdef2));
}
@@ -4627,9 +4635,9 @@ DEFUN ("face-attributes-as-vector", Fface_attributes_as_vector,
/* If the distance (as returned by color_distance) between two colors is
less than this, then they are considered the same, for determining
- whether a color is supported or not. The range of values is 0-65535. */
+ whether a color is supported or not. The range of values is 0-100. */
-#define TTY_SAME_COLOR_THRESHOLD 10000
+#define TTY_SAME_COLOR_THRESHOLD 2.3
#ifdef HAVE_WINDOW_SYSTEM
@@ -4897,7 +4905,7 @@ tty_supports_face_attributes_p (struct frame *f,
distance between the standard foreground and background. */
if (STRINGP (fg) && STRINGP (bg))
{
- int delta_delta
+ double delta_delta
= (color_distance (&fg_std_color, &bg_std_color)
- color_distance (&fg_tty_color, &bg_tty_color));
if (delta_delta > TTY_SAME_COLOR_THRESHOLD
diff --git a/src/xterm.c b/src/xterm.c
index bdc21e6de0..8cb203d418 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -27,6 +27,8 @@ along with GNU Emacs. If not, see . */
#include
#endif
+#include
+
#include "lisp.h"
#include "blockinput.h"
@@ -2372,18 +2374,37 @@ x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
a least-squares matching, which is what X uses for closest
color matching with StaticColor visuals. */
int nearest, i;
- int max_color_delta = 255;
- int max_delta = 3 * max_color_delta;
- int nearest_delta = max_delta + 1;
+ cmsFloat64Number max_color_delta = 100.0f;
+ cmsFloat64Number max_delta = 3 * max_color_delta;
+ cmsFloat64Number nearest_delta = max_delta + 1;
int ncells;
const XColor *cells = x_color_cells (dpy, &ncells);
-
+ cmsHPROFILE profile_in, profile_out;
+ cmsHTRANSFORM transform;
+ cmsCIELab Lab;
+ cmsUInt16Number rgb[3];
+
+ profile_in = cmsCreate_sRGBProfile();
+ profile_out = cmsCreateLab4Profile(NULL);
+ transform = cmsCreateTransform(profile_in, TYPE_RGB_16,
+ profile_out, TYPE_Lab_DBL,
+ INTENT_PERCEPTUAL, 0);
+ cmsCloseProfile(profile_in);
+ cmsCloseProfile(profile_out);
+ rgb[0] = color->red;
+ rgb[1] = color->green;
+ rgb[2] = color->blue;
+ cmsDoTransform(transform, rgb, &Lab, 1);
for (nearest = i = 0; i < ncells; ++i)
{
- int dred = (color->red >> 8) - (cells[i].red >> 8);
- int dgreen = (color->green >> 8) - (cells[i].green >> 8);
- int dblue = (color->blue >> 8) - (cells[i].blue >> 8);
- int delta = dred * dred + dgreen * dgreen + dblue * dblue;
+ cmsCIELab Labi;
+ cmsUInt16Number rgbi[3];
+
+ rgbi[0] = cells[i].red;
+ rgbi[1] = cells[i].green;
+ rgbi[2] = cells[i].blue;
+ cmsDoTransform(transform, rgbi, &Labi, 1);
+ cmsFloat64Number delta = cmsCIE2000DeltaE(&Lab, &Labi, 1.0f, 1.0f, 1.0f);
if (delta < nearest_delta)
{
@@ -2391,7 +2412,7 @@ x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
nearest_delta = delta;
}
}
-
+ cmsDeleteTransform(transform);
color->red = cells[nearest].red;
color->green = cells[nearest].green;
color->blue = cells[nearest].blue;