bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#41544: 26.3; Possible incorrect results from color-distance


From: Mattias Engdegård
Subject: bug#41544: 26.3; Possible incorrect results from color-distance
Date: Thu, 28 May 2020 19:31:51 +0200

[CC:ing Tom Tromey, who used colour-distance in css-mode]

Ah, where to begin. Clearly a distance metric ought to be symmetric; as you 
note, this is easily fixed by replacing the shift by division, which has the 
extra benefit of not relying on the implementation-defined behaviour when 
right-shifting negative values in C. The extra cost is negligible.

Looking at it a bit closer, it seems a waste to use full 16 bit colour channels 
only to shift out 8 of them before getting started. I presume this was done 
partly in order to follow the Riedersma metric more closely, and partly to stay 
within 32 bit numbers (I note that the code uses the C 'long' type, which is 
almost always a mistake). Using 64-bit arithmetic costs us next to nothing 
today, and this solves several problems.

But a darker cloud is on the horizon. Since the Emacs implementation omits the 
square root of the result, it no longer satisfies the triangle inequality, 
which is even more fundamental for distance metrics than symmetry. It is good 
enough for comparison of distances, but they can no longer be added, since it's 
not a true metric.

In fact, it seems that users of color_distance are confused as well: a comment 
says

  /* 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.  */

  #define TTY_SAME_COLOR_THRESHOLD  10000

which is a lie, since color_distance can return values well above 65535.
Some uses are very questionable, given that it's the square of a metric:

      int 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
          || delta_delta < -TTY_SAME_COLOR_THRESHOLD)

So what to do? Best would be to do the arithmetic on the entire channel values 
and take the square root at the end; the cost is nothing to worry about on 
hardware less than 30 years old. Some constants used for comparison would need 
to be adjusted: the above-mentioned TTY_SAME_COLOR_THRESHOLD (10000), 
face-near-same-threshold (30000), and a number in css--contrasty-color 
(292485).  At least the last should probably use the luma norm originally 
proposed instead (see bug#25525); the use of colour-distance here cannot be 
right.







reply via email to

[Prev in Thread] Current Thread [Next in Thread]