Skip to content

Commit e54a9eb

Browse files
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. SOLARIZED HEX --------- ------- yellow #b58900 orange #cb4916 red #dc2f51 magenta #bb36d3 violet #6c76c4 blue #268bd2 cyan #2aa189 green #189900
1 parent 62f656a commit e54a9eb

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed

utils/generate-redgreen

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#!/usr/bin/env perl
2+
3+
# This script modifies the Solarized palette to have as high contrast as
4+
# possible for red-green colorblind people. It keeps the saturation/lightness
5+
# of all colors the same, as well as the hues of blue & yellow. It simply
6+
# modifies the hues of the other colors so they are evenly spaced between blue
7+
# and yellow (on the red side), and green/cyan get flipped back onto the green
8+
# side. Running the script produces:
9+
#
10+
# SOLARIZED HEX
11+
# --------- -------
12+
# yellow #b58900
13+
# orange #cb4916
14+
# red #dc2f51
15+
# magenta #bb36d3
16+
# violet #6c76c4
17+
# blue #268bd2
18+
# cyan #2aa189
19+
# green #189900
20+
#
21+
# Try to keep the values above up to date!
22+
23+
use strict;
24+
use warnings;
25+
26+
sub rgb_to_hsl {
27+
my ($r, $g, $b) = @_;
28+
29+
my $max = $r > $g ? $r : $g;
30+
$max = $max > $b ? $max : $b;
31+
32+
my $min = $r < $g ? $r : $g;
33+
$min = $min < $b ? $min : $b;
34+
35+
my $h;
36+
if ($max == $min) {
37+
$h = 0;
38+
} elsif ($max == $r) {
39+
$h = (0 + ($g - $b) / ($max - $min)) / 6;
40+
} elsif ($max == $g) {
41+
$h = (2 + ($b - $r) / ($max - $min)) / 6;
42+
} else {
43+
$h = (4 + ($r - $g) / ($max - $min)) / 6;
44+
}
45+
$h += 1 if $h < 0;
46+
47+
my $l = ($max + $min) / 2;
48+
49+
my $s;
50+
if ($max == 0 || $min == 1) {
51+
$s = 0;
52+
} else {
53+
$s = ($max - $l) / ($l < 0.5 ? $l : 1 - $l);
54+
}
55+
56+
return ($h, $s, $l);
57+
}
58+
59+
sub fmod2 {
60+
my $x = shift;
61+
my $x_ = int($x);
62+
return $x - $x_ + ($x_ & 1);
63+
}
64+
65+
sub hsl_to_rgb {
66+
my ($h, $s, $l) = @_;
67+
68+
my $c = (1 - abs(2 * $l - 1)) * $s;
69+
70+
my $h_ = $h * 6;
71+
my $x = $c * (1 - abs(fmod2($h_) - 1));
72+
my ($r_, $g_, $b_);
73+
if (0 <= $h_ && $h_ < 1) {
74+
($r_, $g_, $b_) = ($c, $x, 0);
75+
} elsif (1 <= $h_ && $h_ < 2) {
76+
($r_, $g_, $b_) = ($x, $c, 0);
77+
} elsif (2 <= $h_ && $h_ < 3) {
78+
($r_, $g_, $b_) = (0, $c, $x);
79+
} elsif (3 <= $h_ && $h_ < 4) {
80+
($r_, $g_, $b_) = (0, $x, $c);
81+
} elsif (4 <= $h_ && $h_ < 5) {
82+
($r_, $g_, $b_) = ($x, 0, $c);
83+
} else {
84+
($r_, $g_, $b_) = ($c, 0, $x);
85+
}
86+
87+
my $m = $l - $c / 2;
88+
return ($r_ + $m, $g_ + $m, $b_ + $m);
89+
}
90+
91+
sub hex_to_rgb {
92+
my $color = shift;
93+
die unless $color =~ /^#(?:[0-9A-Fa-f]{3}){1,2}$/;
94+
$color = substr $color, 1;
95+
96+
my $val = hex $color;
97+
my ($r, $g, $b);
98+
if (length $color == 3) {
99+
$b = $val & 0xf; $b |= $b << 4; $val >>= 4;
100+
$g = $val & 0xf; $g |= $g << 4; $val >>= 4;
101+
$r = $val & 0xf; $r |= $r << 4;
102+
} else {
103+
$b = $val & 0xff; $val >>= 8;
104+
$g = $val & 0xff; $val >>= 8;
105+
$r = $val & 0xff;
106+
}
107+
108+
return ($r / 255.0, $g / 255.0, $b / 255.0);
109+
}
110+
111+
sub hex_to_hsl {
112+
rgb_to_hsl(hex_to_rgb(shift));
113+
}
114+
115+
sub rgb_to_hex {
116+
my ($r, $g, $b) = @_;
117+
$r = int($r * 255.0 + 0.5);
118+
$g = int($g * 255.0 + 0.5);
119+
$b = int($b * 255.0 + 0.5);
120+
my $val = ($r << 16) | ($g << 8) | $b;
121+
sprintf '#%06x', $val;
122+
}
123+
124+
sub hsl_to_hex {
125+
rgb_to_hex(hsl_to_rgb(@_));
126+
}
127+
128+
129+
130+
# Note that all components are in [0,1] (Except hue, which won't be 1.).
131+
my @yellow = hex_to_hsl('#b58900');
132+
my @orange = hex_to_hsl('#cb4b16');
133+
my @red = hex_to_hsl('#dc322f');
134+
my @magenta = hex_to_hsl('#d33682');
135+
my @violet = hex_to_hsl('#6c71c4');
136+
my @blue = hex_to_hsl('#268bd2');
137+
my @cyan = hex_to_hsl('#2aa198');
138+
my @green = hex_to_hsl('#859900');
139+
140+
# Divide hue space into 7 regions.
141+
my $step = ($yellow[0] - $blue[0] + 1) / 7;
142+
143+
# Generate the six intermediate hues.
144+
my @hues = ($blue[0]);
145+
for my $i (1..6) {
146+
my $next = $hues[$#hues] + $step;
147+
$next -= 1 if $next >= 1;
148+
push @hues, $next;
149+
}
150+
shift @hues; # Remove blue.
151+
152+
# To flip green/cyan back to the correct side. So pick a line that bisects the
153+
# hue wheel and adjust based off that. Note that both of these are the same
154+
# line, just different directions.
155+
my $red_side = ($blue[0] + $yellow[0] + 1) / 2;
156+
my $green_side = $red_side - 0.5;
157+
158+
my @ordered = (\@violet, \@cyan, \@magenta, \@green, \@red, \@orange);
159+
160+
# Update the hues of intermediate colors. Note that this produces identical
161+
# results for HSV because they define hue the same.
162+
for my $i (0..$#ordered) {
163+
my $hue = $ordered[$i][0];
164+
if ($hue > $yellow[0] && $hue < $blue[0]) {
165+
# green side
166+
$hue = $green_side - ($hues[$i] - $red_side);
167+
} else {
168+
# red side
169+
$hue = $hues[$i];
170+
}
171+
$ordered[$i][0] = $hue;
172+
}
173+
174+
print <<END;
175+
SOLARIZED HEX
176+
--------- -------
177+
yellow @{[hsl_to_hex(@yellow )]}
178+
orange @{[hsl_to_hex(@orange )]}
179+
red @{[hsl_to_hex(@red )]}
180+
magenta @{[hsl_to_hex(@magenta)]}
181+
violet @{[hsl_to_hex(@violet )]}
182+
blue @{[hsl_to_hex(@blue )]}
183+
cyan @{[hsl_to_hex(@cyan )]}
184+
green @{[hsl_to_hex(@green )]}
185+
END

0 commit comments

Comments
 (0)