2016-06-27 15 views
0

Das hat mich für ein bisschen gestört, und ich bin mir nicht sicher, ob es eine Antwort gibt. Ich weiß, dass es Module wie Love2D gibt, die Farbverläufe erzeugen, und ich nehme an, dass RGB-Farbgebung verwendet wird. Allerdings muss ich mit xterm 256 Farben etwas Ähnliches finden, aber ich kann nirgendwo eine Gradientenkarte finden, die dabei hilft.Lua - xterm 256 Farbverlauf Scripting

Meine Vermutung ist, dass ich eine "am nächsten zur RGB-Farbe" erstellen und einen Farbverlauf daraus erstellen muss, die entsprechende RBG mit dem nächsten xterm übereinstimmen, aber ganz ehrlich, ich weiß es nicht einmal wo soll ich damit anfangen? Ich weiß, dass es in Python ein Skript "convert xterm in RGB hex" gibt (here), aber da ich Python nicht kenne, weiß ich nicht, wie ich das in Lua umwandeln soll.

Letztlich, was ich tun möchte, ist in der Lage, Text mehr oder weniger in einen Regenbogen Farbverlauf zu verwandeln. Ich habe derzeit eine Funktion, um xterm Farben zurückzugeben, aber es ist völlig zufällig, und die Ausgabe kann ein bisschen hart zu lesen sein. Hier ist, was ich für diesen Code habe. Die @x steht für "convert to xterm color", gefolgt von einem dreistelligen Code (001 bis 255) gefolgt von dem Text.

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 

So würde zum Beispiel print(rainbow("Test")) ergeben:

@[email protected]@[email protected]

Offensichtlich ist dies kein Gefälle ist, und nicht das, was ich mit will am Ende. Ist das, was ich will, möglich oder ist es ein verlorener Grund?

bearbeiten
Ich kenne die limitiations von 256 Farben, und ich weiß, dass es nicht eine ganze Menge Spielraum. Wie in dem Kommentar erwähnt, würde es viele gleiche Farbabgleiche geben, also würde ich eine Reihe der gleichen Farben bekommen. Das ist in Ordnung für mich. Egal wie viele tatsächliche Übergänge es macht, ich möchte, dass es einen Gradienten simuliert.

Was wäre schön, wenn ich mindestens in der Lage wäre, Farbgruppen korrekt zu erstellen, ohne die Diagramme abfragen zu müssen. Ich schätze, ich muss eine Tabelle mit "kompatiblen Farbschemata" erstellen und damit arbeiten, es sei denn, jemand hat eine bessere Idee.

+2

Erstens haben Sie wahrscheinlich nicht genügend Schattierungen von einem Farbton, um einen RGB-Farbverlauf korrekt einer beliebigen 256-Farben-Palette zuzuordnen. Wenn Sie Ihre eigene Palette zur Laufzeit definieren könnten, könnten Sie damit durchkommen, aber es könnte sehr viele Farben erfordern. Zweitens, selbst mit 256 Farben, die für einen einzelnen Gradienten verwendet werden, werden Sie wahrscheinlich mit ernsthaften Banden enden. Dies liegt daran, dass viele RGB-Farben in Ihrer neuen Palette der gleichen Farbe zugeordnet werden. Also müssen Sie zusätzlich zu den Farben auch Dithering durchführen. – bodangly

+0

Richtig, ich bin mir der Beschränkungen von 256 Farben bewusst, aber letztendlich möchte ich einfach etwas so genau wie möglich simulieren. Ich nehme an, dass ich zumindest möchte, dass der erste xterm-Wert randomisiert wird, und dann schrittweise die darauf basierende Schattierung erhöht/verringert. Ich weiß aber, dass es ziemlich lang ist. – Josh

Antwort

1

definieren nearest_term256_color_index Funktion:

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 

definieren generate_gradient Funktion, die @x... in Ihren Text eingefügt:

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 

-Test es in Terminal:

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) 

rainbow() ist kein Gradient, es wäre eine Kette von mehreren Gradienten.

+0

Das ist einfach unglaublich. Danke für die Arbeit, die du in diese Arbeit gesteckt hast, Egor. Du hast es immer noch nicht geschafft, mich zu überraschen. – Josh