parse_color function refactoring:

- simplified parsing logic,
- return nil for incorrect input,
- update tests and doc.
This commit is contained in:
MoreThanOneAnimal 2016-11-20 00:40:56 -08:00
parent 51bbb53b30
commit 495e579fdb
2 changed files with 51 additions and 32 deletions

View File

@ -22,51 +22,50 @@ local pattern_cache
--- Parse a HTML-color. --- Parse a HTML-color.
-- This function can parse colors like `#rrggbb` and `#rrggbbaa` and also `red`. -- This function can parse colors like `#rrggbb` and `#rrggbbaa` and also `red`.
-- Thanks to #lua for this. :) -- Max 4 chars per channel. Thanks to #lua for this. :)
-- --
-- @param col The color to parse -- @param col The color to parse
-- @return 4 values which each are in the range [0, 1]. -- @return 4 values representing color in RGBA format (each of them in [0, 1]
-- range) or nil if input is incorrect.
-- @usage -- This will return 0, 1, 0, 1 -- @usage -- This will return 0, 1, 0, 1
-- gears.color.parse_color("#00ff00ff") -- gears.color.parse_color("#00ff00ff")
function color.parse_color(col) function color.parse_color(col)
local rgb = {} local rgb = {}
-- Is it a HTML-style color?
if string.match(col, "^#%x+$") then if string.match(col, "^#%x+$") then
-- Get all hex chars local hex_str = col:sub(2, #col)
for char in string.gmatch(col, "[^#]") do local channels
table.insert(rgb, tonumber(char, 16) / 0xf) if #hex_str % 3 == 0 then
channels = 3
elseif #hex_str % 4 == 0 then
channels = 4
else
return nil
end end
-- Merge consecutive values until we have at most four groups (rgba) local chars_per_channel = #hex_str / channels
local factor = 0xf if chars_per_channel > 4 then
while #rgb > 4 do return nil
local merged = {}
local key, value = next(rgb, nil)
local next_factor = (factor + 1)*(factor + 1) - 1
while key do
local key2, value2 = next(rgb, key)
local v1, v2 = value * factor, value2 * factor
local new = v1 * (factor + 1) + v2
table.insert(merged, new / next_factor)
key, value = next(rgb, key2)
end end
rgb = merged local dividor = 0x10^chars_per_channel - 1
factor = next_factor for idx=1,#hex_str,chars_per_channel do
local channel_val = tonumber(hex_str:sub(idx,idx+chars_per_channel-1), 16)
table.insert(rgb, channel_val / dividor)
end
if channels == 3 then
table.insert(rgb, 1)
end end
else else
-- Let's ask Pango for its opinion (but this doesn't support alpha!)
local c = Pango.Color() local c = Pango.Color()
if c:parse(col) then if not c:parse(col) then
return nil
end
rgb = { rgb = {
c.red / 0xffff, c.red / 0xffff,
c.green / 0xffff, c.green / 0xffff,
c.blue / 0xffff, c.blue / 0xffff,
1.0
} }
end end
end assert(#rgb == 4, col)
-- Add missing groups (missing alpha)
while #rgb < 4 do
table.insert(rgb, 1)
end
return unpack(rgb) return unpack(rgb)
end end

View File

@ -42,6 +42,26 @@ describe("gears.color", function()
test(0x7f, 0xff, 0x00, 0xff, "chartreuse") test(0x7f, 0xff, 0x00, 0xff, "chartreuse")
end) end)
describe("invalid input", function()
local function test_nil(input)
local output = color.parse_color(input)
assert.is_nil(output)
end
it("nonexisting color", function()
test_nil("elephant")
end)
it("invalid format", function()
test_nil('#f0f0f')
end)
it("too long", function()
test_nil("#00000fffff00000fffff")
end)
end)
describe("different lengths", function() describe("different lengths", function()
local function gray(e, e_a, input) local function gray(e, e_a, input)
local o_r, o_g, o_b, o_a, unused = color.parse_color(input) local o_r, o_g, o_b, o_a, unused = color.parse_color(input)