SkyyySi
SkyyySi

Reputation: 73

How to properly convert hsl colors to rgb colors in lua?

I have the following code:

#!/usr/bin/env lua5.3
-- Code adapted from https://github.com/EmmanuelOga/columns/blob/master/utils/color.lua#L51

local function hslToRgb(h, s, l, a)
    local r, g, b

    h = (h / 255)
    s = (s / 100)
    l = (l / 100)

    if s == 0 then
        r, g, b = l, l, l -- achromatic
    else
        local function hue2rgb(p, q, t)
            if t < 0   then t = t + 1 end
            if t > 1   then t = t - 1 end
            if t < 1/6 then return p + (q - p) * 6 * t end
            if t < 1/2 then return q end
            if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end
            return p
        end

        local q
        if l < 0.5 then q = l * (1 + s) else q = l + s - l * s end
        local p = 2 * l - q

        r = hue2rgb(p, q, h + 1/3)
        g = hue2rgb(p, q, h)
        b = hue2rgb(p, q, h - 1/3)
    end

    if not a then a = 1 end
    return r * 255, g * 255, b * 255, a * 255
end

local h,s,l,a
h,s,l,a = hslToRgb(220, 16.4, 21.6)

print(h,s,l,a)
-- expected output: 46  52  64  255
--   actual output: 64.11312    46.04688    60.92496    255

But, as stated at the end, the color values it outputs are completely wrong. The decimals are not an issue (as in, it's not an issue that it outputs them; their values are still wrong).

Upvotes: 1

Views: 2054

Answers (3)

darkfrei
darkfrei

Reputation: 521

-- HSV to RGB
min = math.min
max = math.max
abs = math.abs

local function HSV2RGB (h, s, v)
    local k1 = v*(1-s)
    local k2 = v - k1
    local r = min (max (3*abs (((h      )/180)%2-1)-1, 0), 1)
    local g = min (max (3*abs (((h  -120)/180)%2-1)-1, 0), 1)
    local b = min (max (3*abs (((h  +120)/180)%2-1)-1, 0), 1)
    return k1 + k2 * r, k1 + k2 * g, k1 + k2 * b
end

Upvotes: 1

Ibet43
Ibet43

Reputation: 11

I have been working on a more elegant solution to the HSV to RGB problem for a little bit now and this is what I've come up with.

local ceil = math.ceil
local abs = math.abs

local function clamp(v, min, max)
    if v < min then return min end
    if v > max then return max end
    return v
end

local function HSV(h, s, v)
    local vert = ceil(h / 120)
    local r = abs(((h / 60) - 2 * vert))
    local r, g, b = clamp(r, 1 - s, 1), clamp(2 - r, 1 - s, 1), (1 - s * v)

    if vert == 1 then return r, g, b end
    if vert == 2 then return b, r, g end
    if vert == 3 then return g, b, r end
end

Upvotes: 0

Francisco
Francisco

Reputation: 450

A hue value it's calculated in degrees, so the max isn't 255, but 360:

function hslToRgb(h, s, l)
    h = h / 360
    s = s / 100
    l = l / 100

    local r, g, b;

    if s == 0 then
        r, g, b = l, l, l; -- achromatic
    else
        local function hue2rgb(p, q, t)
            if t < 0 then t = t + 1 end
            if t > 1 then t = t - 1 end
            if t < 1 / 6 then return p + (q - p) * 6 * t end
            if t < 1 / 2 then return q end
            if t < 2 / 3 then return p + (q - p) * (2 / 3 - t) * 6 end
            return p;
        end

        local q = l < 0.5 and l * (1 + s) or l + s - l * s;
        local p = 2 * l - q;
        r = hue2rgb(p, q, h + 1 / 3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1 / 3);
    end

    if not a then a = 1 end
    return r * 255, g * 255, b * 255, a * 255
end

You can see this code working here.

Upvotes: 3

Related Questions