From what I’ve heard normalizing is, that has nothing to do with normalization… Maybe string.style()?
Function - ColorSpace(input,output,...)
– Converts between RGB,HSV,HSL,LCH, and Hex color values
This function is an all in one converter for color spaces, and can convert between most commonly used formats back and forth as well as output the Hex RGB value of a color. I have yet to add HSI however, and am working on this currently
RGB - Red(r) (0 - 255) Green(g) (0 - 255) Blue(b) (0 - 255)
HSV - Hue(h) (0 - 360) Saturation(s) (0 - 1) Value(v) (0 - 1)
HSL - Hue(h) (0 - 360) Saturation(s) (0 - 1) Lightness(l) (0 - 1)
LCH 601 or LCH 709 - Luma(y) (0 - 1) Chroma(c) ( 0 - 1) Hue(h) (0 - 360)
Hex(string) - Standard RGB Color Hex String
To use enter two of the values above as strings for input and output and the vararg takes values either sequentially or as a table sequential or properly keyed.
Update - Currently the most up to date version of this function is at https://github.com/Beckett2000/Color-Space.lua/blob/master/Conversion.lua. This one is for the time being more accurate until I find a better way to post it on these forums.
Changes: Added HSI, Fixed table input issue
I will add a more detailed description of usage later as time permits, but let me know if there are any errors and or areas in need of improvement.
-- Converts Between Color Spaces and Conversions
-- Accepts/Outputs RGB/HSV/HSL/LCH 601/LCH 709/Hex
function ColorSpace(input,output,...)
local In if input and type(input) == "string" then In = string.upper(input)
else print("Input must be valid string.") return end
local Out if output and type(output) == "string" then Out = string.upper(output)
else print("Output must be valid string.") return end
local Values = {...}
local ColorTable = type(Values[1]) == "table"
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Outputs Values Converted to RGB
local function ConversionNS(Input,values)
if #values ~= 1 then local Values = {} -- Color Table Evaluation
if Input == "HSV" then Values.h = values[h] or values[1] Values.s = values[s] or values[2]
Values.v = values[v] or values[3]
elseif Input == "HSL" then Values.h = values[h] or values[1] Values.s = values[s] or values[2]
Values.l = values[l] or values[3]
elseif Input == "LCH 601" or In == "LCH 709" then Values.y = values[y] or values[1]
Values.c = values[c] or values[2] Values.h = values[h] or values[3] end
local Hdash,RGB = Values.h/60,{R = 0, G = 0, B = 0}
local Chroma if Input == "HSV" then Chroma = Values.v * Values.s
elseif Input == "HSL" then Chroma = (1 - math.abs((2 * Values.l) - 1)) * Values.s
elseif Input == "LCH 601" or Input == "LCH 709" then Chroma = Values.c end
local X = Chroma * (1.0 - math.abs((Hdash % 2.0) - 1.0))
if Hdash < 1.0 then RGB.R = Chroma RGB.G = X
elseif Hdash < 2.0 then RGB.R = X RGB.G = Chroma
elseif Hdash < 3.0 then RGB.G = Chroma RGB.B = X
elseif Hdash < 4.0 then RGB.G = X RGB.B = Chroma
elseif Hdash < 5.0 then RGB.R = X RGB.B = Chroma
elseif Hdash < = 6.0 then RGB.R = Chroma RGB.B = X end
local R,G,B = RGB.R,RGB.G,RGB.B
local Min if In == "HSV" then Min = Values.v - Chroma
elseif Input == "HSL" then Min = Values.l - (0.5 * Chroma)
elseif Input == "LCH 601" then Min = Values.y - ((0.2990 * R) + (0.5864 * G) + (0.1146 * B))
elseif Input == "LCH 709" then Min = Values.y - ((0.2126 * R) + (0.7152 * G) + (0.0722 * B)) end
RGB.R = RGB.R + Min RGB.G = RGB.G + Min RGB.B = RGB.B + Min
return {r = RGB.R * 255, g = RGB.G * 255, b = RGB.B * 255}
elseif #values == 1 then -- Converts Hex Values to RGB
if Input == "HEX" then Hexes = {A = 10, B = 11, C = 12, D = 13, E = 14, F = 15}
local RGB = {} for Hex in string.gmatch(values[1],"%w%w") do
local Value = 0 for First,Last in string.gmatch(Hex,"(%w)(%w)") do
if Hexes[string.upper(First)] == nil then Value = Value + (tonumber(First) * 16)
else Value = Value + (Hexes[string.upper(First)] * 16) end
if Hexes[string.upper(Last)] == nil then Value = Value + tonumber(Last)
else Value = Value + Hexes[string.upper(Last)] end end
if RGB.r == nil then RGB.r = Value elseif RGB.g == nil then RGB.g = Value
elseif RGB.b == nil then RGB.b = Value end end
return RGB end end end
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Outputs Values Converted from RGB
local function ConversionS(Output,values)
local R,G,B = values.r or values[1], values.g or values[2], values.b or values[3]
R = R/255 G = G/255 B = B/255 -- Reduces Color Values
local Max,Min = math.max(R,G,B),math.min(R,G,B)
local Chroma if R == 0 or G == 0 or B == 0 then Chroma = Max
else Chroma = Max - Min end
local Hue if Chroma == 0 then Hue = 0
elseif Max == R then Hue = 60 * (((G - B)/Chroma) % 6)
elseif Max == G then Hue = 60 * (((B - R)/Chroma) + 2)
elseif Max == B then Hue = 60 * (((R - G)/Chroma) + 4) end
if Output == "HSV" then -- Hue Saturation Value Space
local V,S = Max if Chroma == 0 then S = 0 else S = Chroma/V end
return {h = Hue, s = S, v = V}
elseif Output == "HSL" then -- Hue Saturation Lightness Space
local L,S = 0.5 * (Max + Min), 0
if Chroma == 0 then S = 0 else S = Chroma / (1 - math.abs((2 * L) - 1)) end
return {h = Hue, s = S, l = L}
elseif Output == "LCH 601" then -- Luma Chroma Hue (NTSC) Space
local Luma = (0.2990 * R) + (0.5864 * G) + (0.1146 * B)
return {y = Luma, c = Chroma, h = Hue}
elseif Output == "LCH 709" then -- Luma Chroma Hue (sRGB) Space
local Luma = (0.2126 * R) + (0.7152 * G) + (0.0722 * B)
return {y = Luma, c = Chroma, h = Hue}
elseif Output == "HEX" then -- Converts Entry to Hex String
local Hex,Val = "#",{"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}
local RGB,Hex = {R * 255,G * 255,B * 255},"#" for _,Col in pairs(RGB) do
local Tens,Ones = math.floor(Col/16), Col % 16 Hex = Hex..Val[Tens + 1]..Val[Ones + 1] end
return Hex end end
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
local Vals if ColorTable then Vals = Values[1]
elseif not ColorTable then Vals = {Values[1],Values[2],Values[3]} end
if In == "RGB" then return ConversionS(Out,Vals)
elseif Out == "RGB" then return ConversionNS(In,Vals)
else local Color = ConversionNS(In,Vals) return ConversionS(Out,Color) end
end
I thought hue was 0-1… It is in an HSV>RGB conversion function I got from the interwebs.
@Beckett2000 - your table comparison doesn’t deal with 2D tables, and there are quite a few existing Lua functions on the net that handle this, and more. It’s fun to write your own, but if you’re planning to share with other Codea users, I suggest you first make sure that there isn’t a much better version out there already, because there are programmers out there who make all of us look like rank amateurs!
Perhaps like this one: http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3
@SkyTheCoder - The Hue from my understanding is an angular measure, and it can be computed to be within a range of 0 - 1, but for display purposes I normalized the value to 360 by multiplying the result by this. This is more evident in things like HSI where you need the angular measure to create the conversion. I put the latest version of my converter in the repository below which normalizes all 0 - 1 values to 0 - 100, 0 - 360 for Hue, and 0 - 255 for HSI intensity. Also above doesn’t actually work with tables, but I fixed that as well.
https://github.com/Beckett2000/Color-Space.lua/blob/master/Conversion.lua
@Ignatz - Thanks for the link. My comparison function does need some more work to be more up to par.