To get a uniform color gradient, fewer colors should be squeezed between close key colors than between distant ones.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- There are two issues with the current pattern colors: * We have lots of blue/green colors which are hard to distinguish. * We have few colors in the yellow/red range despite those being easier to distinguish.
This is in part because we don't take the space between key colors into account, but mainly because interpolating in the RGB colorspace does not yield good results.
So the goal of this patchset is to make it easier to distinguish the pattern colors by fixing these two issues. --- winetest/build-patterns | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/winetest/build-patterns b/winetest/build-patterns index 2ee5d5bdd..ff72516f6 100755 --- a/winetest/build-patterns +++ b/winetest/build-patterns @@ -872,6 +872,13 @@ sub blend($$$) return $r; }
+sub distance($$) +{ + my ($a, $b) = @_; + return sqrt(($b->[0] - $a->[0])**2 + + ($b->[1] - $a->[1])**2 + + ($b->[2] - $a->[2])**2); +}
# Use colors to differentiate the set values. Each unique value is assigned # a color (in HTML format) picked along a series of gradients passing by the @@ -897,19 +904,33 @@ sub compute_set_colors($) # when many colors are needed. $keycolors[0] = [0, 179, 179] if ($count > 10);
+ # Compute the total length of the path traced by the key colors through + # the colorspace. This is necessary so the gradient remains uniform + # even if two key colors are close to each other. This does assume that + # the path does not zigzag too much: (0,0,0)->(255,0,0)->(1,0,0) cannot + # produce a meaningful gradient. + my @keypos = (0); + for (my $i = 1; $i < @keycolors; $i++) + { + my $d = distance($keycolors[$i - 1], $keycolors[$i]); + $keypos[$i] = $keypos[$i - 1] + $d; + } + my $k = 0; - my ($start, $end) = (-1, 0); for (0..$count-1) { - while (!$end or $_ > $end) + # Compute the position of the current item on the path + my $pos = $_ / ($count - 1) * $keypos[-1]; + + # Figure out which segment of the path this corresponds to + while ($pos > $keypos[$k+1] and $k+1 < @keycolors-1) { $k++; - $start = $end; - $end = ($count-1) * $k / (@keycolors-1); } - $set->{$values[$_]} = color2html(blend(($_-$start)/($end-$start), - $keycolors[$k-1], - $keycolors[$k])); + + # And blend + my $Rgb = blend(($pos - $keypos[$k]) / ($keypos[$k+1] - $keypos[$k]), $keycolors[$k], $keycolors[$k+1]); + $set->{$values[$_]} = color2html($Rgb); } } }
Interpolation works best in a colorspace where the distance between colors is representative of their perceptual difference. That's roughly the case in the Luv colorspace and much less so in the RGB one.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- This introduces a dependency on the Graphics::ColorObject perl module which is provided by the libgraphics-colorobject-perl Debian package. Note that on Debian 11 this package is missing a dependency on libgraphics-colornames-www-perl. --- winetest/build-patterns | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/winetest/build-patterns b/winetest/build-patterns index ff72516f6..72291401e 100755 --- a/winetest/build-patterns +++ b/winetest/build-patterns @@ -22,6 +22,7 @@ use open ':utf8'; use CGI qw(:standard); use POSIX; # ceil()
+use Graphics::ColorObject; use Text::CSV::Encoded; use Time::Piece;
@@ -860,15 +861,15 @@ if (open(my $fh, "-|", $cmd)) sub color2html($) { my ($c) = @_; - return sprintf "#%02x%02x%02x", $c->[0], $c->[1], $c->[2]; + return "#". $c->as_RGBhex(); }
-sub blend($$$) +sub interpolate($$$) { my ($p, $start, $end) = @_; - my $r = [int($start->[0] * (1 - $p) + $end->[0] * $p + 0.5), - int($start->[1] * (1 - $p) + $end->[1] * $p + 0.5), - int($start->[2] * (1 - $p) + $end->[2] * $p + 0.5)]; + my $r = [$start->[0] * (1 - $p) + $end->[0] * $p, + $start->[1] * (1 - $p) + $end->[1] * $p, + $start->[2] * (1 - $p) + $end->[2] * $p]; return $r; }
@@ -896,7 +897,7 @@ sub compute_set_colors($) my $count = @values; if ($count == 1) { - $set->{$values[0]} = color2html($keycolors[0]); + $set->{$values[0]} = color2html(Graphics::ColorObject->new_RGB255($keycolors[0])); } else { @@ -904,6 +905,12 @@ sub compute_set_colors($) # when many colors are needed. $keycolors[0] = [0, 179, 179] if ($count > 10);
+ # Convert the key colors to the Luv colorspace where the distance + # between colors is roughly representative of the perceptual difference + # between them. This allows linear interpolation to produce relatively + # uniform gradients (which is not the case in the RGB colorspace). + map { $_ = Graphics::ColorObject->new_RGB255($_)->as_Luv() } @keycolors; + # Compute the total length of the path traced by the key colors through # the colorspace. This is necessary so the gradient remains uniform # even if two key colors are close to each other. This does assume that @@ -929,8 +936,8 @@ sub compute_set_colors($) }
# And blend - my $Rgb = blend(($pos - $keypos[$k]) / ($keypos[$k+1] - $keypos[$k]), $keycolors[$k], $keycolors[$k+1]); - $set->{$values[$_]} = color2html($Rgb); + my $Luv = interpolate(($pos - $keypos[$k]) / ($keypos[$k+1] - $keypos[$k]), $keycolors[$k], $keycolors[$k+1]); + $set->{$values[$_]} = color2html(Graphics::ColorObject->new_Luv($Luv)); } } }
On Tue, 31 Aug 2021, Francois Gouget wrote:
Interpolation works best in a colorspace where the distance between colors is representative of their perceptual difference. That's roughly the case in the Luv colorspace and much less so in the RGB one.
Signed-off-by: Francois Gouget fgouget@codeweavers.com
This introduces a dependency on the Graphics::ColorObject perl module which is provided by the libgraphics-colorobject-perl Debian package. Note that on Debian 11 this package is missing a dependency on libgraphics-colornames-www-perl.
The patterns did not get updated today. I think that's because libgraphics-colorobject-perl is missing on winehq.org.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- winetest/build-patterns | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/winetest/build-patterns b/winetest/build-patterns index 72291401e..386bf9784 100755 --- a/winetest/build-patterns +++ b/winetest/build-patterns @@ -903,7 +903,7 @@ sub compute_set_colors($) { # Start from a 'darker cyan' for increased contrast # when many colors are needed. - $keycolors[0] = [0, 179, 179] if ($count > 10); + unshift @keycolors, [0, 179, 179] if ($count > 10);
# Convert the key colors to the Luv colorspace where the distance # between colors is roughly representative of the perceptual difference