Module:Colour

H萌娘,万物皆可H的百科全书!
跳到导航 跳到搜索
Template-info.svg 模块文档  [创建] [刷新]
local colorKeywords = {
  aliceblue = { 240, 248, 255 },
  antiquewhite = { 250, 235, 215 },
  aqua = { 0, 255, 255 },
  aquamarine = { 127, 255, 212 },
  azure = { 240, 255, 255 },
  beige = { 245, 245, 220 },
  bisque = { 255, 228, 196 },
  black = { 0, 0, 0 },
  blanchedalmond = { 255, 235, 205 },
  blue = { 0, 0, 255 },
  blueviolet = { 138, 43, 226 },
  brown = { 165, 42, 42 },
  burlywood = { 222, 184, 135 },
  cadetblue = { 95, 158, 160 },
  chartreuse = { 127, 255, 0 },
  chocolate = { 210, 105, 30 },
  coral = { 255, 127, 80 },
  cornflowerblue = { 100, 149, 237 },
  cornsilk = { 255, 248, 220 },
  crimson = { 220, 20, 60 },
  cyan = { 0, 255, 255 },
  darkblue = { 0, 0, 139 },
  darkcyan = { 0, 139, 139 },
  darkgoldenrod = { 184, 134, 11 },
  darkgray = { 169, 169, 169 },
  darkgreen = { 0, 100, 0 },
  darkgrey = { 169, 169, 169 },
  darkkhaki = { 189, 183, 107 },
  darkmagenta = { 139, 0, 139 },
  darkolivegreen = { 85, 107, 47 },
  darkorange = { 255, 140, 0 },
  darkorchid = { 153, 50, 204 },
  darkred = { 139, 0, 0 },
  darksalmon = { 233, 150, 122 },
  darkseagreen = { 143, 188, 143 },
  darkslateblue = { 72, 61, 139 },
  darkslategray = { 47, 79, 79 },
  darkslategrey = { 47, 79, 79 },
  darkturquoise = { 0, 206, 209 },
  darkviolet = { 148, 0, 211 },
  deeppink = { 255, 20, 147 },
  deepskyblue = { 0, 191, 255 },
  dimgray = { 105, 105, 105 },
  dimgrey = { 105, 105, 105 },
  dodgerblue = { 30, 144, 255 },
  firebrick = { 178, 34, 34 },
  floralwhite = { 255, 250, 240 },
  forestgreen = { 34, 139, 34 },
  fuchsia = { 255, 0, 255 },
  gainsboro = { 220, 220, 220 },
  ghostwhite = { 248, 248, 255 },
  gold = { 255, 215, 0 },
  goldenrod = { 218, 165, 32 },
  gray = { 128, 128, 128 },
  green = { 0, 128, 0 },
  greenyellow = { 173, 255, 47 },
  grey = { 128, 128, 128 },
  honeydew = { 240, 255, 240 },
  hotpink = { 255, 105, 180 },
  indianred = { 205, 92, 92 },
  indigo = { 75, 0, 130 },
  ivory = { 255, 255, 240 },
  khaki = { 240, 230, 140 },
  lavender = { 230, 230, 250 },
  lavenderblush = { 255, 240, 245 },
  lawngreen = { 124, 252, 0 },
  lemonchiffon = { 255, 250, 205 },
  lightblue = { 173, 216, 230 },
  lightcoral = { 240, 128, 128 },
  lightcyan = { 224, 255, 255 },
  lightgoldenrodyellow = { 250, 250, 210 },
  lightgray = { 211, 211, 211 },
  lightgreen = { 144, 238, 144 },
  lightgrey = { 211, 211, 211 },
  lightpink = { 255, 182, 193 },
  lightsalmon = { 255, 160, 122 },
  lightseagreen = { 32, 178, 170 },
  lightskyblue = { 135, 206, 250 },
  lightslategray = { 119, 136, 153 },
  lightslategrey = { 119, 136, 153 },
  lightsteelblue = { 176, 196, 222 },
  lightyellow = { 255, 255, 224 },
  lime = { 0, 255, 0 },
  limegreen = { 50, 205, 50 },
  linen = { 250, 240, 230 },
  magenta = { 255, 0, 255 },
  maroon = { 128, 0, 0 },
  mediumaquamarine = { 102, 205, 170 },
  mediumblue = { 0, 0, 205 },
  mediumorchid = { 186, 85, 211 },
  mediumpurple = { 147, 112, 219 },
  mediumseagreen = { 60, 179, 113 },
  mediumslateblue = { 123, 104, 238 },
  mediumspringgreen = { 0, 250, 154 },
  mediumturquoise = { 72, 209, 204 },
  mediumvioletred = { 199, 21, 133 },
  midnightblue = { 25, 25, 112 },
  mintcream = { 245, 255, 250 },
  mistyrose = { 255, 228, 225 },
  moccasin = { 255, 228, 181 },
  navajowhite = { 255, 222, 173 },
  navy = { 0, 0, 128 },
  oldlace = { 253, 245, 230 },
  olive = { 128, 128, 0 },
  olivedrab = { 107, 142, 35 },
  orange = { 255, 165, 0 },
  orangered = { 255, 69, 0 },
  orchid = { 218, 112, 214 },
  palegoldenrod = { 238, 232, 170 },
  palegreen = { 152, 251, 152 },
  paleturquoise = { 175, 238, 238 },
  palevioletred = { 219, 112, 147 },
  papayawhip = { 255, 239, 213 },
  peachpuff = { 255, 218, 185 },
  peru = { 205, 133, 63 },
  pink = { 255, 192, 203 },
  plum = { 221, 160, 221 },
  powderblue = { 176, 224, 230 },
  purple = { 128, 0, 128 },
  red = { 255, 0, 0 },
  rosybrown = { 188, 143, 143 },
  royalblue = { 65, 105, 225 },
  saddlebrown = { 139, 69, 19 },
  salmon = { 250, 128, 114 },
  sandybrown = { 244, 164, 96 },
  seagreen = { 46, 139, 87 },
  seashell = { 255, 245, 238 },
  sienna = { 160, 82, 45 },
  silver = { 192, 192, 192 },
  skyblue = { 135, 206, 235 },
  slateblue = { 106, 90, 205 },
  slategray = { 112, 128, 144 },
  slategrey = { 112, 128, 144 },
  snow = { 255, 250, 250 },
  springgreen = { 0, 255, 127 },
  steelblue = { 70, 130, 180 },
  tan = { 210, 180, 140 },
  teal = { 0, 128, 128 },
  thistle = { 216, 191, 216 },
  tomato = { 255, 99, 71 },
  turquoise = { 64, 224, 208 },
  violet = { 238, 130, 238 },
  wheat = { 245, 222, 179 },
  white = { 255, 255, 255 },
  whitesmoke = { 245, 245, 245 },
  yellow = { 255, 255, 0 },
  yellowgreen = { 154, 205, 50 },
}

local module = {}

local getArgs = require('Module:Arguments').getArgs

function random(min, max)
  return mw.getCurrentFrame():expandTemplate{ title = 'random', args = { min, max } }
end

function toRgb(color)
  local r, g, b, opacity
  
  if color:find('^#') then 
    color = color:sub(2)
    if #color == 3 then
      r = color:sub(1, 1)
      g = color:sub(2, 2)
      b = color:sub(3, 3)

      r = r..r
      g = g..g
      b = b..b
    elseif #color == 6 then
      r = color:sub(1, 2)
      g = color:sub(3, 4)
      b = color:sub(5, 6)
    else
      return nil
    end
  end

  if color:find('^rgba?%(.+%)$') then
    if color:find('^rgb%(.+%)$') then
      _, _, r, g, b = color:find('^rgb%(%s-(%d-),%s-(%d-)%s-,%s-(%d-)%s-%)$')
    else
      _, _, r, g, b, opacity = color:find('^rgba%(%s-(%d-),%s-(%d-)%s-,%s-(%d-)%s-,%s-(.+)%s-%)$')

      r = math.floor(r * opacity + 0.5)
      g = math.floor(g * opacity + 0.5)
      b = math.floor(b * opacity + 0.5)
    end
    
    return {
      tonumber(r),
      tonumber(g),
      tonumber(b)
    }
  end
  
  if r ~= nil then
    return {
      tonumber(r, 16),
      tonumber(g, 16),
      tonumber(b, 16)
    }
  else
    return colorKeywords[color]
  end
end


function toCssColor(rgbArr, opacity, isHex)
  local method = 'rgb'
  if opacity then
  	method = 'rgba'
  	table.insert(rgbArr, opacity)
  end
  
  function toHex(num)
  	local int, float = math.modf(num)
  	if float > 0.4 then int = int + 1 end
    local zero = ''
  	if int < 16 then zero = '0' end
  	return zero..string.format('%X', int)
  end
  
  if isHex then
  	return '#'..toHex(rgbArr[1])..toHex(rgbArr[2])..toHex(rgbArr[3])
  else
	return method..'('..table.concat(rgbArr, ',')..')'
  end
end

function isLight(rgbArr)
  return rgbArr[1] * 0.299 + rgbArr[2] * 0.578 + rgb[3] * 0.114 >= 192
end

function _main(args)
  local action = args[1]
  local arg1 = args[2]
  local arg2 = args[3]
  if action == 'reverse' then
    local rgb = toRgb(arg1) 
    for i, v in ipairs(rgb) do
      rgb[i] = math.abs(v - 255)
    end
    return toCssColor(rgb, false, arg2)
  end

  if action == 'random' then
    local min = 0
    local max = 255
    if arg2 then
      min = arg1
      max = arg2
    elseif args1 then
      min = args1
    end

    local rgb = {
      random(min, max),
      random(min, max),
      random(min, max)
    }

    return toCssColor(rgb, false, arg2)
  end
  
  if action == 'rgba' then
    local rgb = toRgb(arg1)
  	return toCssColor(rgb, arg2) 
  end

  if action == 'isLight' then
    return isLight(toRgb(arg1)) and 1 or ''
  end

  if action == 'isDark' then
    return isLight(toRgb(arg1)) == false and 1 or ''
  end

  if action:find('^[%+%-]') or action == 'test' then
    local rgb = toRgb(arg1)
    local tenth = {}
    for i, v in ipairs(rgb) do
      tenth[i] = {
        ['-'] = (255 - v) / 10,
        ['+'] = - v / 10
      }
    end

    function block(text, color)
      return '<ruby style="color:'..color..'">■<rt style="color:black">'..text..'<rt></ruby>&nbsp;'
    end

    function compute(operator, degree)
      local rgbClone = { rgb[1], rgb[2], rgb[3] }
      for i, v in ipairs(rgbClone) do
        rgbClone[i] = v + tenth[i][operator] * degree
        if rgbClone[i] < 0 then rgbClone[i] = 0 end
        if rgbClone[i] > 255 then rgbClone[i] = 255 end
      end
      return rgbClone
    end

    if action == 'test' then
      local left = ''
      local right = ''
      for i=1, 9 do
        left = block('-'..i, toCssColor(compute('-', i), false, arg2))..left
        right = right..block('+'..i, toCssColor(compute('+', i), false, arg2))
      end
      return '<div style="font-size:30px">'..left..block('▼', toCssColor(rgb, false, arg2))..right..'</div>'
    end
    
    local level = 1
    if action:find('%d$') then
      local plus = tonumber(action:match('(%d)$'))
      if plus > 9 then plus = 9 end
      level = plus
    end

    local operator = action:sub(1, 1)
    return toCssColor(compute(operator, level), false, arg2)
  end
end

function module.main(frame)
	local args = getArgs(frame)
	return _main(args)
end

return module