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

From: Mattias Engdegård <[email-masked]>
Date: Wed, 10 Jun 2020 16:51:24 +0200

9 juni 2020 kl. 18.20 skrev Eli Zaretskii <[email-masked]>:

>> Let's consider the three saturated colours #ff0000 (red), #00ff00 (green) and #0000ff (blue). Black text looks terrible on blue, as does white on green; black on red isn't good either. This comes as no surprise: the human eye is more sensitive to brightness levels of green than blue, with red somewhere in-between.
> 
> Here we already not necessarily agree: at least on some text-mode
> terminals some of the above combinations look quite legible to me.

Of course there will be some terminals where some of the combinations are legible. But that wasn't the point, the point being that they are less legible that the alternative, and on most terminals substantially so.

> Like I said: individual taste and differences, as well as different
> RGB values used by some terminals for the same color names, can and do
> wreak havoc on this, so a perfect solution is simply not possible.

Nowhere did I claim perfection; let's tuck away the straw men. However, I do think we should strive to do as well as we can, and I think I'm not alone. This is not a matter of individual taste: colour perception is a science.

It is true that Emacs sometimes doesn't know the exact colours used by the terminal, but that is a problem that the old code suffers from as well. Maybe the old predicates are more robust for bad input? Unfortunately, there is no evidence of this at all; I've experimented with many terminals and settings. See further below for a counter-example.

> Again, I see no practical problems described here, just a theoretical
> issue with the particular implementations we have now.  Those
> implementations do their job, although they are clearly not perfect.
> However, I seed no reason to seek perfection in this case.

Again, it is not a matter of perfection but about being better. Or more critically, avoiding being bad. The new predicate almost never gives bad results; the old ones often do.

If you want to argue for the old code, please come up with precise examples of colours for which they avoid a bad decision while colour-dark-p does not. You could also show how the old predicates are better than the new one in a majority of cases. Describe the circumstances (environment, configuration etc) so that they can be reproduced.

Meanwhile, here are two screenshots of Emacs displaying some lisp code, both using XTerm version 328, configured for 256 colours, with TERM=xterm-256color, and the same background, without any Emacs customisation.

First, without the patch:

Next, with the patch:

This particular background is taken from the XTerm's 256-colour palette used by Emacs, and there are many more in that set exhibiting similar problems. Obviously, with 24-bit colour terminals, there is a large number of colours that cause trouble for the old heuristics.

> IMO, the commentary here doesn't explain enough, and actually begs
> more questions than it answers.  What is "gamma-correction", and why
> is it pertinent here?  Why is the power 2.2 a "good enough"
> approximation here?  What are the other constants, and what is the
> meaning of each one of them?  And pointing to the bug number for
> rationale of the cut-off value doesn't really help, since the
> discussion is very long, so I doubt people will easily find that
> rationale.

Fair enough -- I thought that the programmers who don't already know the theory would immediately look it up, but I've added a link to Wikipedia.

> I still don't understand why we need this function.  Did you see any
> practical problems with using color-name-to-rgb?  Why does it matter
> that it needs the display to be initialized?  Would it be enough to
> document that it needs the display to be initialized?

If we use color-name-to-rgb then we get a crash on start-up with TERM=xterm (for example), as explained before. I agree it's a somewhat artificial function; I've eliminated it in the attached patch.

> As I said before, I don't want to change the default value of
> frame-background-mode.  This code has been relatively stable for quite
> some time, and the result is customizable if the user doesn't like the
> default.  Changing the default value in subtle ways simply risks
> annoying users.  There's nothing to gain here, only potential losses.

Quite the contrary: the new predicate is more robust than the old one, which I have argued with both concrete examples and theory. If you disagree, please supply both: why the AVG predicate is better, and specifically for what colours.
There is nothing to lose here, only potential gains.

Here is another screenshot: it compares the three old predicates with the new one for all colours in an Xterm with TERM=xterm-16color. The left-hand columns show the contrasting decision with each colour as background, the right-hand columns with the same colour as foreground. max, avg and dist refer to the old predicates as per previous message; new is color-dark-p of the patch.

Here is the same comparison on a terminal configured with the exact colours of a Linux VGA console, TERM=linux:

Note how the Emacs's RGB values are far off (especially the brownish shade that it thinks is bright yellow), yet the new predicate does better than all the old ones here.

> Note that AFAIR CSS (and HTML in general) uses 24 BPP colors, whereas
> your color-dark-p is AFAICT based on 16-bit color values, not 8-bit.

No, CSS and Emacs normalise hex colours to the number of digits used, so that #123, #112233 and #111122223333 all represent the same colour. (The Windows-specific colour parser has a bug, as mentioned recently on emacs-devel; I intend to fix that since other colour parsers are buggy in other ways. This is completely unrelated to the current discussion.)