Syntax Shortening / Useful Functions

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.