|
| 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