Jos*_*osh 1 lua gradient colors 256color
这个问题困扰了我一段时间,我不确定是否有答案。我知道有像 Love2D 这样的模块可以完成渐变,我猜它使用 RGB 着色。然而,我需要使用 xterm 256 颜色找到非常相似的东西,但我似乎无法在任何地方找到渐变贴图来帮助实现这一点。
我的猜测是,我必须创建一个“最接近 RGB 颜色”并从中创建一个渐变,将相应的 RBG 与最近的 xterm 匹配相匹配,但说实话,我什至不知道从哪里开始这。我知道Python中有一个“将xterm转换为RGB十六进制”脚本(位于此处),但由于我不了解Python,所以我不知道如何将其转换为Lua。
最终,我想做的是能够将文本或多或少地变成彩虹渐变。我目前有一个返回 xterm 颜色的函数,但它是完全随机的,并且输出可能有点难以阅读。这是我对该代码的内容。代表@x“转换为 xterm 颜色”,后面跟着一个三位数代码(001 到 255),然后是文本。
function rainbow(text)
local rtext = ""
local xcolor = 1
local sbyte = 1
for i = 1, #text do
math.randomseed(os.time() * xcolor * sbyte)
sbyte = string.byte(i)
xcolor = math.random(1, 255)
rtext = rtext .. "@x" .. string.rep("0", 3 - string.len(xcolor)) .. xcolor .. text:sub(i,i)
end
return rtext
end
Run Code Online (Sandbox Code Playgroud)
因此,例如,print(rainbow("Test"))会导致:
@x211T@x069e@x154s@x177t
显然,这不是渐变,也不是我想要的结果。我想要的是否可能实现,还是注定失败?
编辑
我知道 256 色的局限性,而且我知道没有太多的回旋余地。正如评论中指出的,会有很多相同的颜色匹配,所以我会得到一串相同颜色的字符串。这对我来说很好,真的。无论它进行多少次实际转换,我都希望它能够紧密模拟渐变。
如果我能够至少正确地创建颜色组而不必轮询图表,那就太好了。我想,我最终可能要做的是创建一个“兼容的配色方案”表并使用它,除非有人有更好的主意。
定义nearest_term256_color_index函数:
local abs, min, max, floor = math.abs, math.min, math.max, math.floor
local levels = {[0] = 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff}
local function index_0_5(value) -- value = color component 0..255
return floor(max((value - 35) / 40, value / 58))
end
local function nearest_16_231(r, g, b) -- r, g, b = 0..255
-- returns color_index_from_16_to_231, appr_r, appr_g, appr_b
r, g, b = index_0_5(r), index_0_5(g), index_0_5(b)
return 16 + 36 * r + 6 * g + b, levels[r], levels[g], levels[b]
end
local function nearest_232_255(r, g, b) -- r, g, b = 0..255
local gray = (3 * r + 10 * g + b) / 14
-- this is a rational approximation for well-known formula
-- gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
local index = min(23, max(0, floor((gray - 3) / 10)))
gray = 8 + index * 10
return 232 + index, gray, gray, gray
end
local function color_distance(r1, g1, b1, r2, g2, b2)
return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2)
end
local function nearest_term256_color_index(r, g, b) -- r, g, b = 0..255
local idx1, r1, g1, b1 = nearest_16_231(r, g, b)
local idx2, r2, g2, b2 = nearest_232_255(r, g, b)
local dist1 = color_distance(r, g, b, r1, g1, b1)
local dist2 = color_distance(r, g, b, r2, g2, b2)
return dist1 < dist2 and idx1 or idx2
end
Run Code Online (Sandbox Code Playgroud)
定义插入文本的generate_gradient函数:@x...
local unpack, tonumber = table.unpack or unpack, tonumber
local function convert_color_to_table(rrggbb)
if type(rrggbb) == "string" then
local r, g, b = rrggbb:match"(%x%x)(%x%x)(%x%x)"
return {tonumber(r, 16), tonumber(g, 16), tonumber(b, 16)}
else
return rrggbb
end
end
local function round(x)
return floor(x + 0.5)
end
local function generate_gradient(text, first_color, last_color)
local r, g, b = unpack(convert_color_to_table(first_color))
local dr, dg, db = unpack(convert_color_to_table(last_color))
local char_pattern = "[^\128-\191][\128-\191]*"
local n = max(1, select(2, text:gsub(char_pattern, "")) - 1)
dr, dg, db = (dr - r)/n, (dg - g)/n, (db - b)/n
local result = ""
for c in text:gmatch(char_pattern) do
result = result..("@x%03d"):format(nearest_term256_color_index(
round(r), round(g), round(b)))..c
r, g, b = r + dr, g + dg, b + db
end
return result
end
Run Code Online (Sandbox Code Playgroud)
在终端内测试它:
local function print_with_colors(str)
print(
str:gsub("@x(%d%d%d)",
function(color_idx)
return "\27[38;5;"..color_idx.."m"
end)
.."\27[0m"
)
end
local str = "Gradient"
local blue, red = {0, 0, 255}, "#FF0000"
str = generate_gradient(str, blue, red) -- gradient from blue to red
print(str)
print_with_colors(str)
Run Code Online (Sandbox Code Playgroud)
rainbow()不是梯度,它将是几个梯度的链。