mirror of
https://github.com/altercation/solarized
synced 2024-11-21 19:23:02 +00:00
Script to make palette for R-G-colorblindness
This produces an adjusted Solarized palette that evenly spaces hues between blue & yellow, keeping everything else the same. It gives the highest possible contrast for Deuteranopia. For terminals with 24-bit color support, it also displays the palette. SOLARIZED HEX --------- ------- yellow #b58900 orange #cb4916 red #dc2f51 magenta #bb36d3 violet #6c76c4 blue #268bd2 cyan #2aa189 green #189900
This commit is contained in:
parent
62f656a02f
commit
62d5af8bad
1 changed files with 235 additions and 0 deletions
235
utils/generate-redgreen
Executable file
235
utils/generate-redgreen
Executable file
|
@ -0,0 +1,235 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
# This script modifies the Solarized palette to have as high contrast as
|
||||
# possible for red-green colorblind people. It keeps the saturation/lightness
|
||||
# of all colors the same, as well as the hues of blue & yellow. It simply
|
||||
# modifies the hues of the other colors so they are evenly spaced between blue
|
||||
# and yellow (on the red side), and green/cyan get flipped back onto the green
|
||||
# side. Running the script produces:
|
||||
#
|
||||
# SOLARIZED HEX
|
||||
# --------- -------
|
||||
# yellow #b58900
|
||||
# orange #cb4916
|
||||
# red #dc2f51
|
||||
# magenta #bb36d3
|
||||
# violet #6c76c4
|
||||
# blue #268bd2
|
||||
# cyan #2aa189
|
||||
# green #189900
|
||||
#
|
||||
# Try to keep the values above up to date!
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub rgb_to_hsl {
|
||||
my ($r, $g, $b) = @_;
|
||||
|
||||
my $max = $r > $g ? $r : $g;
|
||||
$max = $max > $b ? $max : $b;
|
||||
|
||||
my $min = $r < $g ? $r : $g;
|
||||
$min = $min < $b ? $min : $b;
|
||||
|
||||
my $h;
|
||||
if ($max == $min) {
|
||||
$h = 0;
|
||||
} elsif ($max == $r) {
|
||||
$h = (0 + ($g - $b) / ($max - $min)) / 6;
|
||||
} elsif ($max == $g) {
|
||||
$h = (2 + ($b - $r) / ($max - $min)) / 6;
|
||||
} else {
|
||||
$h = (4 + ($r - $g) / ($max - $min)) / 6;
|
||||
}
|
||||
$h += 1 if $h < 0;
|
||||
|
||||
my $l = ($max + $min) / 2;
|
||||
|
||||
my $s;
|
||||
if ($max == 0 || $min == 1) {
|
||||
$s = 0;
|
||||
} else {
|
||||
$s = ($max - $l) / ($l < 0.5 ? $l : 1 - $l);
|
||||
}
|
||||
|
||||
return ($h, $s, $l);
|
||||
}
|
||||
|
||||
sub fmod2 {
|
||||
my $x = shift;
|
||||
my $x_ = int($x);
|
||||
return $x - $x_ + ($x_ & 1);
|
||||
}
|
||||
|
||||
sub hsl_to_rgb {
|
||||
my ($h, $s, $l) = @_;
|
||||
|
||||
my $c = (1 - abs(2 * $l - 1)) * $s;
|
||||
|
||||
my $h_ = $h * 6;
|
||||
my $x = $c * (1 - abs(fmod2($h_) - 1));
|
||||
my ($r_, $g_, $b_);
|
||||
if (0 <= $h_ && $h_ < 1) {
|
||||
($r_, $g_, $b_) = ($c, $x, 0);
|
||||
} elsif (1 <= $h_ && $h_ < 2) {
|
||||
($r_, $g_, $b_) = ($x, $c, 0);
|
||||
} elsif (2 <= $h_ && $h_ < 3) {
|
||||
($r_, $g_, $b_) = (0, $c, $x);
|
||||
} elsif (3 <= $h_ && $h_ < 4) {
|
||||
($r_, $g_, $b_) = (0, $x, $c);
|
||||
} elsif (4 <= $h_ && $h_ < 5) {
|
||||
($r_, $g_, $b_) = ($x, 0, $c);
|
||||
} else {
|
||||
($r_, $g_, $b_) = ($c, 0, $x);
|
||||
}
|
||||
|
||||
my $m = $l - $c / 2;
|
||||
return ($r_ + $m, $g_ + $m, $b_ + $m);
|
||||
}
|
||||
|
||||
sub hex_to_rgb {
|
||||
my $color = shift;
|
||||
die unless $color =~ /^#(?:[0-9A-Fa-f]{3}){1,2}$/;
|
||||
$color = substr $color, 1;
|
||||
|
||||
my $val = hex $color;
|
||||
my ($r, $g, $b);
|
||||
if (length $color == 3) {
|
||||
$b = $val & 0xf; $b |= $b << 4; $val >>= 4;
|
||||
$g = $val & 0xf; $g |= $g << 4; $val >>= 4;
|
||||
$r = $val & 0xf; $r |= $r << 4;
|
||||
} else {
|
||||
$b = $val & 0xff; $val >>= 8;
|
||||
$g = $val & 0xff; $val >>= 8;
|
||||
$r = $val & 0xff;
|
||||
}
|
||||
|
||||
return ($r / 255.0, $g / 255.0, $b / 255.0);
|
||||
}
|
||||
|
||||
sub hex_to_hsl {
|
||||
rgb_to_hsl(hex_to_rgb(shift));
|
||||
}
|
||||
|
||||
sub rgb_to_hex {
|
||||
my ($r, $g, $b) = @_;
|
||||
$r = int($r * 255.0 + 0.5);
|
||||
$g = int($g * 255.0 + 0.5);
|
||||
$b = int($b * 255.0 + 0.5);
|
||||
my $val = ($r << 16) | ($g << 8) | $b;
|
||||
sprintf '#%06x', $val;
|
||||
}
|
||||
|
||||
sub hsl_to_hex {
|
||||
rgb_to_hex(hsl_to_rgb(@_));
|
||||
}
|
||||
|
||||
# Print the colors using ANSI 24-bit color escapes.
|
||||
sub show_colors {
|
||||
for my $color (@_) {
|
||||
my ($r, $g, $b) = hsl_to_rgb(@$color);
|
||||
my $ansi = sprintf '2;%d;%d;%d',
|
||||
int($r * 255.0 + 0.5),
|
||||
int($g * 255.0 + 0.5),
|
||||
int($b * 255.0 + 0.5);
|
||||
print "\e[48;${ansi}m ";
|
||||
}
|
||||
print "\e[m\n";
|
||||
}
|
||||
|
||||
# The values are kinda made up. But if the hue is on the green side, it gets
|
||||
# flipped to the red side and the saturation is reduced by 50%.
|
||||
sub flat_filter {
|
||||
my ($hue, $sat, $lig) = @_;
|
||||
my $yellow = 60.0 / 360.0;
|
||||
my $blue = 240.0 / 360.0;
|
||||
|
||||
if ($hue > $yellow && $hue < $blue) {
|
||||
my $mid_green = ($blue + $yellow) / 2.0;
|
||||
my $mid_red = $mid_green + 0.5;
|
||||
$hue = $mid_red - ($hue - $mid_green);
|
||||
$hue -= 1.0 if $hue >= 1.0;
|
||||
$sat *= 0.5;
|
||||
}
|
||||
($hue, $sat, $lig);
|
||||
}
|
||||
|
||||
|
||||
# Note that all components are in [0,1] (Except hue, which won't be 1.).
|
||||
my @yellow = hex_to_hsl('#b58900');
|
||||
my @orange = hex_to_hsl('#cb4b16');
|
||||
my @red = hex_to_hsl('#dc322f');
|
||||
my @magenta = hex_to_hsl('#d33682');
|
||||
my @violet = hex_to_hsl('#6c71c4');
|
||||
my @blue = hex_to_hsl('#268bd2');
|
||||
my @cyan = hex_to_hsl('#2aa198');
|
||||
my @green = hex_to_hsl('#859900');
|
||||
|
||||
my @spectrum = (
|
||||
\@magenta, \@red, \@orange, \@yellow,
|
||||
\@green, \@cyan, \@blue, \@violet,
|
||||
);
|
||||
|
||||
# Try to show what the current colors look like, along with what (I think)
|
||||
# it'd look like for deuteranopia.
|
||||
print "Solarized regular: ";
|
||||
show_colors(@spectrum);
|
||||
print "Solarized flat: ";
|
||||
show_colors(map { [flat_filter @$_] } @spectrum);
|
||||
|
||||
# Divide hue space into 7 regions.
|
||||
my $step = ($yellow[0] - $blue[0] + 1) / 7;
|
||||
|
||||
# Generate the six intermediate hues.
|
||||
my @hues = ($blue[0]);
|
||||
for my $i (1..6) {
|
||||
my $next = $hues[$#hues] + $step;
|
||||
$next -= 1 if $next >= 1;
|
||||
push @hues, $next;
|
||||
}
|
||||
shift @hues; # Remove blue.
|
||||
|
||||
# To flip green/cyan back to the correct side. So pick a line that bisects the
|
||||
# hue wheel and adjust based off that. Note that both of these are the same
|
||||
# line, just different directions.
|
||||
my $yellow = 60.0 / 360.0;
|
||||
my $blue = 240.0 / 360.0;
|
||||
my $green_mid = ($yellow + $blue) / 2.0;
|
||||
my $red_mid = $green_mid + 0.5;
|
||||
|
||||
my @ordered = (\@violet, \@cyan, \@magenta, \@green, \@red, \@orange);
|
||||
|
||||
# Update the hues of intermediate colors. Note that this produces identical
|
||||
# results for HSV because they define hue the same.
|
||||
for my $i (0..$#ordered) {
|
||||
my $hue = $ordered[$i][0];
|
||||
if ($hue > $yellow && $hue < $blue) {
|
||||
# green side
|
||||
$hue = $green_mid - ($hues[$i] - $red_mid);
|
||||
$hue -= 1.0 if $hue >= 1.0;
|
||||
} else {
|
||||
# red side
|
||||
$hue = $hues[$i];
|
||||
}
|
||||
$ordered[$i][0] = $hue;
|
||||
}
|
||||
|
||||
print "Solarized-RG regular: ";
|
||||
show_colors(@spectrum);
|
||||
print "Solarized-RG flat: ";
|
||||
show_colors(map { [flat_filter @$_] } @spectrum);
|
||||
|
||||
print <<END;
|
||||
|
||||
SOLARIZED HEX
|
||||
--------- -------
|
||||
yellow @{[hsl_to_hex(@yellow )]}
|
||||
orange @{[hsl_to_hex(@orange )]}
|
||||
red @{[hsl_to_hex(@red )]}
|
||||
magenta @{[hsl_to_hex(@magenta)]}
|
||||
violet @{[hsl_to_hex(@violet )]}
|
||||
blue @{[hsl_to_hex(@blue )]}
|
||||
cyan @{[hsl_to_hex(@cyan )]}
|
||||
green @{[hsl_to_hex(@green )]}
|
||||
END
|
Loading…
Reference in a new issue