Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

rgb2hsl - Something fun I wrote today #90

Open
dylanaraps opened this issue Oct 1, 2019 · 3 comments
Open

rgb2hsl - Something fun I wrote today #90

dylanaraps opened this issue Oct 1, 2019 · 3 comments

Comments

@dylanaraps
Copy link
Owner

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

georgalis commented Oct 1, 2019 via email

@dylanaraps
Copy link
Owner Author

dylanaraps commented Oct 1, 2019

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

ogdenjosh commented Oct 1, 2019

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants