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)); } } }