Editing Module:Color contrast

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. Read the Privacy Policy to learn what information we collect about you and how we use it.

If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 2: Line 2:
-- This module implements  
-- This module implements  
--  {{Color contrast ratio}}
--  {{Color contrast ratio}}
--  {{Greater color contrast ratio}}
--  {{ColorToLum}}
--  {{ColorToLum}}
--  {{RGBColorToLum}}
--  {{RGBColorToLum}}
--
--
local p = {}
local p = {}
local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' )


local function sRGB ( v )  
local function sRGB ( v )  
Line 14: Line 12:
else
else
v = math.pow((v+0.055)/1.055, 2.4)
v = math.pow((v+0.055)/1.055, 2.4)
end
    end
return v
return v
end
local function rgbdec2lum( R, G, B )
if ( 0 <= R and R < 256 and 0 <= G and G < 256 and 0 <= B and B < 256 ) then
return 0.2126 * sRGB(R/255) + 0.7152 * sRGB(G/255) + 0.0722 * sRGB(B/255)
else
return ''
end
end
local function hsl2lum( h, s, l )
if ( 0 <= h and h < 360 and 0 <= s and s <= 1 and 0 <= l and l <= 1 ) then
local c = (1 - math.abs(2*l - 1))*s
local x = c*(1 - math.abs( math.fmod(h/60, 2) - 1) )
local m = l - c/2
local r, g, b = m, m, m
if( 0 <= h and h < 60 ) then
r = r + c
g = g + x
elseif( 60 <= h and h < 120 ) then
r = r + x
g = g + c
elseif( 120 <= h and h < 180 ) then
g = g + c
b = b + x
elseif( 180 <= h and h < 240 ) then
g = g + x
b = b + c
elseif( 240 <= h and h < 300 ) then
r = r + x
b = b + c
elseif( 300 <= h and h < 360 ) then
r = r + c
b = b + x
end
return rgbdec2lum(255*r, 255*g, 255*b)
else
return ''
end
end
end


local function color2lum( c )
local function color2lum( c )
 
if (c == nil) then
if (c == nil) then
return ''
return ''
end
end


-- html '#' entity
local HTMLcolor = {
c = c:gsub("&#35;", "#")
white = 1,
 
silver = 0.52711512570581,
-- whitespace
gray = 0.2158605001139,
c = c:match( '^%s*(.-)[%s;]*$' )
black = 0,
 
red = 0.2126,
-- unstrip nowiki strip markers
maroon = 0.045891942324215,
c = mw.text.unstripNoWiki(c)
yellow = 0.9278,
olive = 0.20027537200568,
lime = 0.7152,
green = 0.15438342968146,
aqua = 0.7874,
teal = 0.16996855778968,
blue = 0.0722,
navy = 0.015585128108224,
fuchsia = 0.2848,
purple = 0.061477070432439,
orange = 0.4817026703631,


gold = 0.69860877428159,
pink = 0.63271070702466,
lightpink = 0.58566152734898,
hotpink = 0.34658438169715,
deeppink = 0.23866895828276,
palevioletred = 0.28754994117889,
mediumvioletred = 0.14371899849357,
lightsalmon = 0.4780675225206,
salmon = 0.36977241527596,
darksalmon = 0.40541471563381,
lightcoral = 0.35522120733135,
indianred = 0.21406134963884,
crimson = 0.16042199953026,
firebrick = 0.10724525535015,
darkred = 0.054889674531132,
orangered = 0.25516243753416,
tomato = 0.30638612719415,
coral = 0.37017930872924,
darkorange = 0.40016167026524,
lightyellow = 0.98161818392882,
lemonchiffon = 0.94038992245622,
lightgoldenrodyellow = 0.93348351018297,
papayawhip = 0.87797100199835,
moccasin = 0.80083000991567,
peachpuff = 0.74905589878251,
palegoldenrod = 0.78792647887614,
khaki = 0.77012343394121,
darkkhaki = 0.45747326349994,
cornsilk = 0.93562110372965,
blanchedalmond = 0.85084439608156,
bisque = 0.80732327372979,
navajowhite = 0.76519682342785,
wheat = 0.74909702820482,
burlywood = 0.51559844533893,
tan = 0.48237604163921,
rosybrown = 0.32319457649407,
sandybrown = 0.46628543696283,
goldenrod = 0.41919977809569,
darkgoldenrod = 0.27264703559993,
peru = 0.30113074877936,
chocolate = 0.23898526114557,
saddlebrown = 0.097922285020521,
sienna = 0.13697631337098,
brown = 0.098224287876511,
}
    -- whitespace
    c = c:match( '^%s*(.-)%s*$' )
   
-- lowercase
-- lowercase
c = c:lower()
c = c:lower()
 
-- first try to look it up
-- first try to look it up
local L = HTMLcolor[c]
local L = HTMLcolor[c]
Line 81: Line 97:
return L
return L
end
end
  -- convert from hsl
  if mw.ustring.match(c,'^hsl%([%s]*[0-9][0-9%.]*[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then
local h, s, l = mw.ustring.match(c,'^hsl%([%s]*([0-9][0-9%.]*)[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$')
return hsl2lum(tonumber(h), tonumber(s)/100, tonumber(l)/100)
  end
  -- convert from rgb
  if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*%)$') then
local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*%)$')
return rgbdec2lum(tonumber(R), tonumber(G), tonumber(B))
  end
  -- convert from rgb percent
  if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then
local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$')
return rgbdec2lum(255*tonumber(R)/100, 255*tonumber(G)/100, 255*tonumber(B)/100)
  end
-- remove leading # (if there is one) and whitespace
-- remove leading # (if there is one) and whitespace
c = mw.ustring.match(c, '^[%s#]*([a-f0-9]*)[%s]*$')
c = mw.ustring.match(c, '^[%s#]*([a-f0-9]*)[%s]*$')
Line 106: Line 103:
local cs = mw.text.split(c or '', '')
local cs = mw.text.split(c or '', '')
if( #cs == 6 ) then
if( #cs == 6 ) then
local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2])
local R = sRGB( (16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2]))/255 )
local G = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4])
local G = sRGB( (16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4]))/255 )
local B = 16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6])
local B = sRGB( (16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6]))/255 )
 
return rgbdec2lum(R, G, B)
L = 0.2126 * R + 0.7152 * G + 0.0722 * B
return L
elseif ( #cs == 3 ) then
elseif ( #cs == 3 ) then
local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1])
local R = sRGB( (16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1]))/255 )
local G = 16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2])
local G = sRGB( (16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2]))/255 )
local B = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3])
local B = sRGB( (16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3]))/255 )
 
return rgbdec2lum(R, G, B)
L = 0.2126 * R + 0.7152 * G + 0.0722 * B
return L
end
end
 
-- failure, return blank
-- failure, return blank
return ''
return ''
end
end


function p._greatercontrast(args)
local function colors2ratio(c1,c2)
local bias = tonumber(args['bias'] or '0') or 0
local v1 = color2lum(c1)
local css = (args['css'] and args['css'] ~= '') and true or false
local v1 = color2lum(args[1] or '')
local c2 = args[2] or '#FFFFFF'
local v2 = color2lum(c2)
local v2 = color2lum(c2)
local c3 = args[3] or '#000000'
local v3 = color2lum(c3)
local ratio1 = -1;
local ratio2 = -1;
if (type(v1) == 'number' and type(v2) == 'number') then
if (type(v1) == 'number' and type(v2) == 'number') then
ratio1 = (v2 + 0.05)/(v1 + 0.05)
return (v2 + 0.05)/(v1 + 0.05)
ratio1 = (ratio1 < 1) and 1/ratio1 or ratio1
end
if (type(v1) == 'number' and type(v3) == 'number') then
ratio2 = (v3 + 0.05)/(v1 + 0.05)
ratio2 = (ratio2 < 1) and 1/ratio2 or ratio2
end
if css then
local c1 = args[1] or ''
if mw.ustring.match(c1, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
mw.ustring.match(c1, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
c1 = '#' .. c1
end
if mw.ustring.match(c2, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
mw.ustring.match(c2, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
c2 = '#' .. c2
end
if mw.ustring.match(v3, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
mw.ustring.match(v3, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
c3 = '#' .. c3
end
return 'background-color:' .. c1 .. '; color:' .. ((ratio1 > 0) and (ratio2 > 0) and ((ratio1 + bias > ratio2) and c2 or c3) or '') .. ';'
end
return (ratio1 > 0) and (ratio2 > 0) and ((ratio1 + bias > ratio2) and c2 or c3) or ''
end
 
function p._ratio(args)
local v1 = color2lum(args[1])
local v2 = color2lum(args[2])
if (type(v1) == 'number' and type(v2) == 'number') then
-- v1 should be the brighter of the two.
if v2 > v1 then
v1, v2 = v2, v1
end
return (v1 + 0.05)/(v2 + 0.05)
else
else
return args['error'] or '?'
return ''
end
end
 
function p._styleratio(args)
local style = (args[1] or ''):lower()
local bg, fg = 'white', 'black'
local lum_bg, lum_fg = 1, 0
 
if args[2] then
local lum = color2lum(args[2])
if lum ~= '' then bg, lum_bg = args[2], lum end
end
if args[3] then
local lum = color2lum(args[3])
if lum ~= '' then fg, lum_fg = args[3], lum end
end
 
local slist = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(style or '', '&#[Xx]23;', '#'), '&#35;', '#'), ';')
for k = 1,#slist do
local s = slist[k]
local k,v = s:match( '^[%s]*([^:]-):([^:]-)[%s;]*$' )
k = k or ''
v = v or ''
if (k:match('^[%s]*(background)[%s]*$') or k:match('^[%s]*(background%-color)[%s]*$')) then
local lum = color2lum(v)
if( lum ~= '' ) then bg, lum_bg = v, lum end
elseif (k:match('^[%s]*(color)[%s]*$')) then
local lum = color2lum(v)
if( lum ~= '' ) then bg, lum_fg = v, lum end
end
end
if lum_bg > lum_fg then
return (lum_bg + 0.05)/(lum_fg + 0.05)
else
return (lum_fg + 0.05)/(lum_bg + 0.05)
end
end
end
end
Line 216: Line 137:


function p.ratio(frame)
function p.ratio(frame)
local args = frame.args[1] and frame.args or frame:getParent().args
local r = colors2ratio(
return p._ratio(args)
frame.args[1] or frame:getParent().args[1],
end
frame.args[2] or frame:getParent().args[2]
 
)
function p.styleratio(frame)
if (r ~= '') then
local args = frame.args[1] and frame.args or frame:getParent().args
return r
return p._styleratio(args)
else
end
return frame.args['error'] or frame:getParent().args['error'] or '?'
 
end
function p.greatercontrast(frame)
local args = frame.args[1] and frame.args or frame:getParent().args
return p._greatercontrast(args)
end
end
 
return p
return p
Please note that all contributions to Nonbinary Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see Nonbinary Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)

Template used on this page: