2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:ColorManipulation

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

本模块封装一系列简单的色彩操作,以适应不同的使用需求。

功能函数

应被模板封装以提供对外使用的接口。

p.luminThres

为颜色的亮度设置一个门限值,当超过该门限值时自动降低亮度。

  • 输入
  • 颜色代码
  • 门限值,取值为0~1。
  • 输出:处理后的颜色代码。

p.valThres

为颜色的明度设置一个门限值,当超过该门限值时自动降低亮度。

  • 输入
  • 颜色代码
  • 门限值,取值为0~1。
  • 输出:处理后的颜色代码。

p.hueShift

对颜色的色相进行增减操作。

  • 输入
  • 颜色代码
  • 偏移度(以360为整个色环)
  • 输出:处理后的颜色代码。

p.colorMix

混合两种颜色。

  • 输入
  • 两个颜色各自的颜色代码
  • 两种颜色在混合时的权重,取值为0~1;越靠近0点第一种颜色的权重越大,反之亦然。
  • 输出:处理后的颜色代码。

辅助函数

文本处理

parseString

校验输入的十六进制颜色代码并转换为RGB值。

  • 输入:
  • 颜色代码
  • 输出
  • RGB值
  • 指定原颜色代码是否带#号的标识(0为无,1为有)

parseRGB

将输入的RGB值转换为十六进制颜色代码。

  • 输入:
  • RGB值
  • 指定原颜色代码是否带#号的标识(0为无,1为有)
  • 输出
  • 颜色代码,以原格式输出

HSL颜色

rgbToHsl

将RGB颜色转换为HSL颜色。

  • 输入:
  • RGB值
  • 输出
  • HSL值

hslToRgb

将HSL颜色转换为RGB颜色。

  • 输入:
  • HSL值
  • 输出
  • RGB值

HSV颜色

rgbToHsv

将RGB颜色转换为HSV颜色。

  • 输入:
  • RGB值
  • 输出
  • HSV值

hsvToRgb

将HSV颜色转换为RGB颜色。

  • 输入:
  • HSV值
  • 输出
  • RGB值

XYZ颜色

  • 本模板XYZ颜色的Y值为相对亮度 (Relative Luminance),选用CIE 1931 XYZ标准中定义的参数,即Web Content Accessibility Guidelines 2.0标准中相应的相对亮度定义。
  • 根据该标准中的参数,对RGB向XYZ的转换,其内部处理过程如下:
  • 将原始的sRGB值标准化(重新映射):
  • R,G,B值为原始值的1/255
  • 对于R值,若R<=0.03928,则标准化的Rnom值为R/12.92,否则为((R+0.055)/1.055)^2.4
  • G, B的计算方法相同。
  • 将R/G/B值矩阵乘以下列矩阵:
0.4124564 0.3575761 0.1804375
0.2126729 0.7151522 0.0721750
0.0193339 0.1191920 0.9503041
  • 得到的新矩阵分别代表X, Y与Z值。
  • 相应的,将XYZ向RGB转换的逆操作则需作相应的逆运算,即乘上逆矩阵并经反函数处理(反标准化)得到RGB值。

rgbToXyz

将RGB颜色转换为XYZ颜色。

  • 输入:
  • RGB值
  • 输出
  • XYZ值

xyzToRgb

将XYZ颜色转换为RGB颜色。

  • 输入:
  • XYZ值
  • 输出
  • RGB值
p = {}

p["LuminThres"] = function(frame)
    local colorString = frame.args[1]
    local lumThreshold = frame.args[2]
    return p.luminThres(colorString, lumThreshold)
end

-- 为HSL颜色的L设置门限值,在超过门限值时自动降低。
-- Arg: Hex, 门限值
-- Return: 处理后的颜色的Hex
function p.luminThres(colorString, lumThreshold)
  r,g,b,flag = parseString(colorString)
  h,s,l = rgbToHsl(r,g,b)
  l = math.min(lumThreshold, l)
  r,g,b = hslToRgb(h,s,l)
  return parseRGB(r,g,b,flag)
end

p["ValThres"] = function(frame)
    local colorString = frame.args[1]
    local valThreshold = frame.args[2]
    return p.valThres(colorString, valThreshold)
end

-- 为HSV颜色的V设置门限值,在超过门限值时自动降低。
-- Arg: Hex, 门限值
-- Return: 处理后的颜色的Hex
function p.valThres(colorString, valThreshold)
  r,g,b,flag = parseString(colorString)
  h,s,v = rgbToHsv(r,g,b)
  v = math.min(valThreshold, v)
  r,g,b = hsvToRgb(h,s,v)
  return parseRGB(r,g,b,flag)
end

p["HueShift"] = function(frame)
    local colorString = frame.args[1]
    local shift = frame.args[2]
    return p.hueShift(colorString, shift)
end

-- 对HSL颜色的H进行偏移。
-- Arg: Hex, 偏移值(整个色环为360度)
-- Return: 处理后的颜色的Hex
function p.hueShift(colorString, shift)
  r,g,b,flag = parseString(colorString)
  h,s,l = rgbToHsl(r,g,b)
  h = h+shift/360
  r,g,b = hslToRgb(h,s,l)
  return parseRGB(r,g,b,flag)
end

p["ColorMix"] = function(frame)
    local colorString1 = frame.args[1]
    local colorString2 = frame.args[2]
    local weight = frame.args[3]
    return p.colorMix(colorString1, colorString2, weight)
end

-- 以取RGB均值的方式混合颜色
-- Arg: 两个颜色各自的Hex, 权值
-- Return: 混合后的颜色的Hex
function p.colorMix(colorString1, colorString2, weight)
  r1,g1,b1,flag1 = parseString(colorString1)
  r2,g2,b2,flag2 = parseString(colorString2)
  r = r1*(1-weight) + r2*weight
  g = g1*(1-weight) + g2*weight
  b = b1*(1-weight) + b2*weight
  return parseRGB(r,g,b,flag1)
end

-- Helper function: 将RGB值转换为Hex
-- Arg: R, G, B, 输出模式(0 = 不带#号 / 1 = 带#号)
-- Return: Hex
function parseRGB(r,g,b,mode)
  -- 四舍五入处理
  r=math.floor(math.max(math.min(r + 0.5, 255),0))
  g=math.floor(math.max(math.min(g + 0.5, 255),0))
  b=math.floor(math.max(math.min(b + 0.5, 255),0))
  colorNumber = r * 65536 + g * 256 + b
  colorString = string.format("%06X",colorNumber) -- padding
  if(mode == 0) then return colorString end
  if(mode == 1) then return "#"..colorString end
end

-- Helper function: 检测Hex值是否合法,并将Hex转换为RGB值
-- Arg: Hex
-- Return: R, G, B, 输出模式(0 = 不带#号 / 1 = 带#号)
-- TODO: 三位Color Hex、Web Color名
function parseString(colorString)
  length = #colorString
  startWith, endWith = string.find(colorString,"[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]")
  if(string.sub(colorString, 1, 1) == "#" and startWith == 2 and endWith == 7 and length == 7) then
    colorString = (string.sub(colorString, 2))
    colorNumber = tonumber(colorString, 16)
    r = math.floor(colorNumber / 65536)
    g = math.floor(colorNumber / 256 % 256)
    b = colorNumber % 256
    return r,g,b,1
  elseif(startWith == 1 and endWith == 6 and length == 6) then
    colorNumber = tonumber(colorString, 16)
    r = math.floor(colorNumber / 65536)
    g = math.floor(colorNumber / 256 % 256)
    b = colorNumber % 256
    return r,g,b,0
  end
end

-- ref from http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function rgbToHsl(r, g, b)
  r, g, b = r / 255, g / 255, b / 255

  local max, min = math.max(r, g, b), math.min(r, g, b)
  local h, s, l

  l = (max + min) / 2

  if max == min then
    h, s = 0, 0 -- achromatic
  else
    d = max - min
    if l > 0.5 then s = d / (2 - max - min) else s = d / (max + min) end
    if max == r then
      h = (g - b) / d
      if g < b then h = h + 6 end
    elseif max == g then h = (b - r) / d + 2
    elseif max == b then h = (r - g) / d + 4
    end
    h = h / 6
  end
  return h, s, l
end

-- ref from http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function hslToRgb(h, s, l)
  local r, g, b

  if s == 0 then
    r, g, b = l, l, l -- achromatic
  else
    function hue2rgb(p, q, t)
      if t < 0   then t = t + 1 end
      if t > 1   then t = t - 1 end
      if t < 1/6 then return p + (q - p) * 6 * t end
      if t < 1/2 then return q end
      if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end
      return p
    end

    local q
    if l < 0.5 then q = l * (1 + s) else q = l + s - l * s end
    local p = 2 * l - q

    r = hue2rgb(p, q, h + 1/3)
    g = hue2rgb(p, q, h)
    b = hue2rgb(p, q, h - 1/3)
  end

  return r * 255, g * 255, b * 255
end

-- ref from http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function rgbToHsv(r, g, b)
  r, g, b = r / 255, g / 255, b / 255
  local max, min = math.max(r, g, b), math.min(r, g, b)
  local h, s, v
  v = max

  local d = max - min
  if max == 0 then s = 0 else s = d / max end

  if max == min then
    h = 0 -- achromatic
  else
    if max == r then
    h = (g - b) / d
    if g < b then h = h + 6 end
    elseif max == g then h = (b - r) / d + 2
    elseif max == b then h = (r - g) / d + 4
    end
    h = h / 6
  end
  return h, s, v
end

-- ref from http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function hsvToRgb(h, s, v)
  local r, g, b

  local i = math.floor(h * 6);
  local f = h * 6 - i;
  local p = v * (1 - s);
  local q = v * (1 - f * s);
  local t = v * (1 - (1 - f) * s);
  i = i % 6
  if i == 0 then r, g, b = v, t, p
  elseif i == 1 then r, g, b = q, v, p
  elseif i == 2 then r, g, b = p, v, t
  elseif i == 3 then r, g, b = p, q, v
  elseif i == 4 then r, g, b = t, p, v
  elseif i == 5 then r, g, b = v, p, q
  end
  return r * 255, g * 255, b * 255
end

function rgbToXyz (r, g, b)
  r, g, b = r / 255, g / 255, b / 255

  -- normalize
  if r <= 0.03928 then r = r/12.92
  else r = ((r+0.055)/1.055) ^ 2.4 end
  if g <= 0.03928 then g = g/12.92
  else g = ((g+0.055)/1.055) ^ 2.4 end
  if b <= 0.03928 then b = b/12.92
  else b = ((b+0.055)/1.055) ^ 2.4 end

  -- matrix
  x = r*0.4124564 + g*0.3575761 + b*0.1804375
  y = r*0.2126729 + g*0.7151522 + b*0.0721750
  z = r*0.0193339 + g*0.1191920 + b*0.9503041

  return x,y,z
end

function xyzToRgb (x, y, z)
  -- matrix
  r = x*3.2404542 - y*1.5371385 - z*0.4985314
  g = -x*0.9692660 + y*1.8760108 + z*0.0415560
  b = x*0.0556434 - y*0.2040259 + z*1.0572252

  -- denormalize
  if r <= 0.00303949249 then r = r*12.92
  else r = r^(1/2.4) * 1.055 - 0.055 end
  if g <= 0.00303949249 then g = g*12.92
  else g = g^(1/2.4) * 1.055 - 0.055 end
  if b <= 0.00303949249 then b = b*12.92
  else b = b^(1/2.4) * 1.055 - 0.055 end

  return r*255, g*255, b*255
end

return p