rgb2hsl - Something fun I wrote today
dylanaraps opened this issue · 3 comments
dylanaraps commented
This is very likely not perfect but it seems to pass any RGB color I throw at it.
# rgb2hsl - usage: rgb2hsl r g b
rgb_to_hsl() {
local r g b
local h s l
local min max
# Ensure input is greater than 0.
((r=r < 0 ? 0 : ${1:-0}))
((g=g < 0 ? 0 : ${2:-0}))
((b=b < 0 ? 0 : ${3:-0}))
# Ensure input is lesser than 255.
((r=r > 255 ? 255 : r))
((g=g > 255 ? 255 : g))
((b=b > 255 ? 255 : b))
# Convert RGB value to a 0-100 range.
#
# This is usually a 0-1 range but we
# multiply by 100 to "fake" floating
# point.
((r=r * 100 / 255))
((g=g * 100 / 255))
((b=b * 100 / 255))
# Give the min variable the maximum
# possible value. We must set it to
# something.
((min=255))
# Find the minimum and maximum RGB
# values for use below.
((min=r < min ? r : min))
((max=r > max ? r : max))
((min=g < min ? g : min))
((max=g > max ? g : max))
((min=b < min ? b : min))
((max=b > max ? b : max))
# Calculate the luminace using the
# above values.
((l=(min + max) / 2))
# Calculate the saturation using a
# different formula based on its
# value.
#
# Again, we multiply the values by
# 100 to "fake" floating points.
((s=min == max
? 0
: l < 50
? (max - min) * 100 / (max + min)
: (max - min) * 100 / (200 - max - min)
))
# Calculate the hue based on which
# RGB value is the maximum.
((h=s == 0 ? 0
: r == max
? (g - b) * 100 / (max - min)
: g == max
? 200 + (b - r) * 100 / (max - min)
: b == max
? 400 + (r - g) * 100 / (max - min)
: 0
))
# Convert the calculation result into
# degrees. Divide by 100 to reverse the
# floating point hacks.
((h=h * 60 / 100))
printf '%s\n' "$h $s $l"
}
rgb_to_hsl 18 233 45
georgalis commented
excellent! color transformations are challenging!
here is the best info I have on wavelength to rgb conversion
http://www.physics.sfasu.edu/astro/color/spectra.html
https://www.noah.org/wiki/Wavelength_to_RGB_in_Python
if you search for "wl_to_rgb.py" you'll find repositories
with more color libraries... the function I use accepts a
numerator and denominator, calculates a value between
0 and 1 and transformers it to nm, then to rgb hex color.
(half bash, half python) being able to transform saturation
and brightness on a given hue, would be fantastic everyday!
…On Tue, Oct 1, 2019 at 8:12 AM dylan ***@***.***> wrote:
This is very likely not perfect but it seems to pass any RGB color I throw at it.
# rgb2hsl - usage: rgb2hsl r g b
rgb_to_hsl() {
local r g b
local h s l
local min max
# Ensure input is greater than 0.
((r=r < 0 ? 0 : ${1:-0}))
((g=g < 0 ? 0 : ${2:-0}))
((b=b < 0 ? 0 : ${3:-0}))
# Ensure input is lesser than 255.
((r=r > 255 ? 255 : r))
((g=g > 255 ? 255 : g))
((b=b > 255 ? 255 : b))
# Convert RGB value to a 0-100 range.
#
# This is usually a 0-1 range but we
# multiply by 100 to "fake" floating
# point.
((r=r * 100 / 255))
((g=g * 100 / 255))
((b=b * 100 / 255))
# Give the min variable the maximum
# possible value. We must set it to
# something.
((min=255))
# Find the minimum and maximum RGB
# values for use below.
((min=r < min ? r : min))
((max=r > max ? r : max))
((min=g < min ? g : min))
((max=g > max ? g : max))
((min=b < min ? b : min))
((max=b > max ? b : max))
# Calculate the luminace using the
# above values.
((l=(min + max) / 2))
# Calculate the saturation using a
# different formula based on its
# value.
#
# Again, we multiply the values by
# 100 to "fake" floating points.
((s=min == max
? 0
: l < 50
? (max - min) * 100 / (max + min)
: (max - min) * 100 / (200 - max - min)
))
# Calculate the hue based on which
# RGB value is the maximum.
((h=s == 0 ? 0
: r == max
? (g - b) * 100 / (max - min)
: g == max
? 200 + (b - r) * 100 / (max - min)
: b == max
? 400 + (r - g) * 100 / (max - min)
: 0
))
# Convert the calculation result into
# degrees. Divide by 100 to reverse the
# floating point hacks.
((h=h * 60 / 100))
printf '%s\n' "$h $s $l"
}
rgb_to_hsl 18 233 45
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
--
George Georgalis, (415) 894-2710, http://www.galis.org/
dylanaraps commented
Bonus!
The entire function inside an arithmetic block (( ))
. This really starts to look like another language entirely!
The coolest part:
-> time rgb2hsl
186 100 53
real 0m 0.00s
user 0m 0.00s
sys 0m 0.00s
rgb_to_hsl() ((
r = r < 0 ? 0 : ${1:-0},
g = g < 0 ? 0 : ${2:-0},
b = b < 0 ? 0 : ${3:-0},
r = r > 255 ? 255 : r,
g = g > 255 ? 255 : g,
b = b > 255 ? 255 : b,
r = r * 100 / 255,
g = g * 100 / 255,
b = b * 100 / 255,
min=255,
min = r < min ? r : min,
max = r > max ? r : max,
min = g < min ? g : min,
max = g > max ? g : max,
min = b < min ? b : min,
max = b > max ? b : max,
mid = max - min,
tot = max + min,
l = tot / 2,
s = min == max ? 0
: l < 50
? mid * 100 / tot
: mid * 100 / (200 - max - min),
h = s == 0 ? 0
: r == max
? (g - b) * 100 / mid
: g == max
? 200 + (b - r) * 100 / mid
: b == max
? 400 + (r - g) * 100 / mid
: 0,
h = h * 60 / 100
))
rgb_to_hsl 18 233 255
printf '%s\n' "$h $s $l"
ogdenjosh commented
It seems to be failing with "#944B53" (148, 75, 83).
Looks like this is due to g < b when r == max, since the calculation for h will give us a negative value in this scenario.
EDIT: This seems to work as far as I've tested
# Calculate the hue based on which
# RGB value is the maximum.
((h=s == 0 ? 0
: r == max
? (g - b) * 100 / (max - min)
: g == max
? 200 + (b - r) * 100 / (max - min)
: b == max
? 400 + (r - g) * 100 / (max - min)
: 0
))
# If hue is negative, add 600.
((h=h < 0 ? 600 + h : h))
# Convert the calculation result into
# degrees. Divide by 100 to reverse the
# floating point hacks.
((h=h * 60 / 100))