degesch: pick colours based on relative luminance

Replaces the inaccurate Rec. 709 luma we used to use before.

This is the first feature here that requires libm, which doesn't
seem to be a particularly great sacrifice.

Moreover, I've rectified that the input isn't linear in sRGB,
and then was even normalized wrong for the luma formula.
This commit is contained in:
Přemysl Eric Janouch 2021-06-15 04:35:41 +02:00
parent e3c47c33fa
commit b4dd0052ff
Signed by: p
GPG Key ID: A0420B94F92B9493
3 changed files with 38 additions and 7 deletions

View File

@ -61,7 +61,8 @@ endif ()
# -lrt is only for glibc < 2.17 # -lrt is only for glibc < 2.17
# -liconv may or may not be a part of libc # -liconv may or may not be a part of libc
foreach (extra iconv rt) # -lm may or may not be a part of libc
foreach (extra iconv rt m)
find_library (extra_lib_${extra} ${extra}) find_library (extra_lib_${extra} ${extra})
if (extra_lib_${extra}) if (extra_lib_${extra})
list (APPEND project_libraries ${extra_lib_${extra}}) list (APPEND project_libraries ${extra_lib_${extra}})

View File

@ -51,6 +51,7 @@ enum
#include "common.c" #include "common.c"
#include "kike-replies.c" #include "kike-replies.c"
#include <math.h>
#include <langinfo.h> #include <langinfo.h>
#include <locale.h> #include <locale.h>
#include <pwd.h> #include <pwd.h>
@ -2108,17 +2109,23 @@ filter_color_cube_for_acceptable_nick_colors (size_t *len)
// This is a pure function and we don't use threads, static storage is fine // This is a pure function and we don't use threads, static storage is fine
static int table[6 * 6 * 6]; static int table[6 * 6 * 6];
size_t len_counter = 0; size_t len_counter = 0;
for (int x = 0; x < 6 * 6 * 6; x++) for (int x = 0; x < N_ELEMENTS (table); x++)
{ {
// FIXME this isn't exactly right, the values aren't linear
int r = x / 36; int r = x / 36;
int g = (x / 6) % 6; int g = (x / 6) % 6;
int b = (x % 6); int b = (x % 6);
// Use the luma value of colours within the cube to filter colours that // The first step is 95/255, the rest are 40/255,
// look okay-ish on terminals with both black and white backgrounds // as an approximation we can double the first step
double luma = 0.2126 * r / 6. + 0.7152 * g / 6. + 0.0722 * b / 6.; double linear_R = pow ((r + !!r) / 6., 2.2);
if (luma >= .3 && luma <= .5) double linear_G = pow ((g + !!g) / 6., 2.2);
double linear_B = pow ((b + !!b) / 6., 2.2);
// Use the relative luminance of colours within the cube to filter
// colours that look okay-ish on terminals with both black and white
// backgrounds (use the test-nick-colors script to calibrate)
double Y = 0.2126 * linear_R + 0.7152 * linear_G + 0.0722 * linear_B;
if (Y >= .25 && Y <= .4)
table[len_counter++] = 16 + x; table[len_counter++] = 16 + x;
} }
*len = len_counter; *len = len_counter;

23
test-nick-colors Executable file
View File

@ -0,0 +1,23 @@
#!/bin/sh
# Check whether the terminal colours filtered by our algorithm are legible
export example=$(
tcc "-run -lm" - <<-EOF
#include <stddef.h>
#include <stdio.h>
#include <math.h>
$(perl -0777 -ne 'print $& if /^.*?\nfilter_color(?s:.*?)^}$/m' degesch.c)
void main () {
size_t len = 0;
int *table = filter_color_cube_for_acceptable_nick_colors (&len);
for (size_t i = 0; i < len; i++)
printf ("<@\\x1b[38;5;%dmIRCuser\\x1b[m> I'm typing!\n", table[i]);
}
EOF
)
# Both should give acceptable results,
# which results in a bad compromise that the main author himself needs
xterm -bg black -fg white -e 'echo $example; cat' &
xterm -bg white -fg black -e 'echo $example; cat' &