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;