2012-08-01 17 views
6

Poszukuję algorytmu/sposobu konwersji danego HEX (np. # 111111 R: 0x11, G: 0x11, B: 0x11) na najbliższy numer koloru X11 (Terminal jest albo 88 lub 256 kolorów) przy użyciu skryptu Python, PHP lub VIM i zastanawiałem się, czy ktoś tutaj zna jakiś sposób, czy też wskazuje kierunek, w którym to zrobię.Konwertuj HEX na najbliższy X11 Numer koloru

Dzięki z góry.

+0

Jaki jest * najbliższy *? odpowiedz, a będziesz miał algorytm. czy to jest odległość w przestrzeni trójwymiarowej? lub wolisz zachować proporcje (kolor) lub amplitudę (jasność), itp ..? kiedy masz już metryczny dystans, po prostu wybierasz minimum. –

+0

@KarolyHorvath - Nie jestem pewien, który algorytm może dać mi lepszy wynik, ale wyjaśnię, co próbuję zrobić. Tworzę schemat kolorów dla mojego edytora VIM. Korzystając z GUI w wersji VIM mogę używać kolorów HEX. Teraz chcę przekonwertować ten numer HEX na X11 i ustawić go na konsolową wersję VIM. – markfw

Odpowiedz

7

miałem ten sam problem (biorąc istniejący colorscheme Vima z gVim kolorach sześciokątnych i wypełnienie końcowych wartości kolorów). Oto skrypt użyłem (chociaż funkcja ColorDist prawdopodobnie skorzystają z lepszej metryce odległość kolor jak niektóre inne plakaty sugeruje)

import re 
import math 

colors = { 
    '000000': '16', '00005f': '17', '000087': '18', '0000af': '19', '0000d7': '20', 
    '0000ff': '21', '005f00': '22', '005f5f': '23', '005f87': '24', '005faf': '25', 
    '005fd7': '26', '005fff': '27', '008700': '28', '00875f': '29', '008787': '30', 
    '0087af': '31', '0087d7': '32', '0087ff': '33', '00af00': '34', '00af5f': '35', 
    '00af87': '36', '00afaf': '37', '00afd7': '38', '00afff': '39', '00d700': '40', 
    '00d75f': '41', '00d787': '42', '00d7af': '43', '00d7d7': '44', '00d7ff': '45', 
    '00ff00': '46', '00ff5f': '47', '00ff87': '48', '00ffaf': '49', '00ffd7': '50', 
    '00ffff': '51', '5f0000': '52', '5f005f': '53', '5f0087': '54', '5f00af': '55', 
    '5f00d7': '56', '5f00ff': '57', '5f5f00': '58', '5f5f5f': '59', '5f5f87': '60', 
    '5f5faf': '61', '5f5fd7': '62', '5f5fff': '63', '5f8700': '64', '5f875f': '65', 
    '5f8787': '66', '5f87af': '67', '5f87d7': '68', '5f87ff': '69', '5faf00': '70', 
    '5faf5f': '71', '5faf87': '72', '5fafaf': '73', '5fafd7': '74', '5fafff': '75', 
    '5fd700': '76', '5fd75f': '77', '5fd787': '78', '5fd7af': '79', '5fd7d7': '80', 
    '5fd7ff': '81', '5fff00': '82', '5fff5f': '83', '5fff87': '84', '5fffaf': '85', 
    '5fffd7': '86', '5fffff': '87', '870000': '88', '87005f': '89', '870087': '90', 
    '8700af': '91', '8700d7': '92', '8700ff': '93', '875f00': '94', '875f5f': '95', 
    '875f87': '96', '875faf': '97', '875fd7': '98', '875fff': '99', '878700': '100', 
    '87875f': '101', '878787': '102', '8787af': '103', '8787d7': '104', '8787ff': '105', 
    '87af00': '106', '87af5f': '107', '87af87': '108', '87afaf': '109', '87afd7': '110', 
    '87afff': '111', '87d700': '112', '87d75f': '113', '87d787': '114', '87d7af': '115', 
    '87d7d7': '116', '87d7ff': '117', '87ff00': '118', '87ff5f': '119', '87ff87': '120', 
    '87ffaf': '121', '87ffd7': '122', '87ffff': '123', 'af0000': '124', 'af005f': '125', 
    'af0087': '126', 'af00af': '127', 'af00d7': '128', 'af00ff': '129', 'af5f00': '130', 
    'af5f5f': '131', 'af5f87': '132', 'af5faf': '133', 'af5fd7': '134', 'af5fff': '135', 
    'af8700': '136', 'af875f': '137', 'af8787': '138', 'af87af': '139', 'af87d7': '140', 
    'af87ff': '141', 'afaf00': '142', 'afaf5f': '143', 'afaf87': '144', 'afafaf': '145', 
    'afafd7': '146', 'afafff': '147', 'afd700': '148', 'afd75f': '149', 'afd787': '150', 
    'afd7af': '151', 'afd7d7': '152', 'afd7ff': '153', 'afff00': '154', 'afff5f': '155', 
    'afff87': '156', 'afffaf': '157', 'afffd7': '158', 'afffff': '159', 'd70000': '160', 
    'd7005f': '161', 'd70087': '162', 'd700af': '163', 'd700d7': '164', 'd700ff': '165', 
    'd75f00': '166', 'd75f5f': '167', 'd75f87': '168', 'd75faf': '169', 'd75fd7': '170', 
    'd75fff': '171', 'd78700': '172', 'd7875f': '173', 'd78787': '174', 'd787af': '175', 
    'd787d7': '176', 'd787ff': '177', 'd7af00': '178', 'd7af5f': '179', 'd7af87': '180', 
    'd7afaf': '181', 'd7afd7': '182', 'd7afff': '183', 'd7d700': '184', 'd7d75f': '185', 
    'd7d787': '186', 'd7d7af': '187', 'd7d7d7': '188', 'd7d7ff': '189', 'd7ff00': '190', 
    'd7ff5f': '191', 'd7ff87': '192', 'd7ffaf': '193', 'd7ffd7': '194', 'd7ffff': '195', 
    'ff0000': '196', 'ff005f': '197', 'ff0087': '198', 'ff00af': '199', 'ff00d7': '200', 
    'ff00ff': '201', 'ff5f00': '202', 'ff5f5f': '203', 'ff5f87': '204', 'ff5faf': '205', 
    'ff5fd7': '206', 'ff5fff': '207', 'ff8700': '208', 'ff875f': '209', 'ff8787': '210', 
    'ff87af': '211', 'ff87d7': '212', 'ff87ff': '213', 'ffaf00': '214', 'ffaf5f': '215', 
    'ffaf87': '216', 'ffafaf': '217', 'ffafd7': '218', 'ffafff': '219', 'ffd700': '220', 
    'ffd75f': '221', 'ffd787': '222', 'ffd7af': '223', 'ffd7d7': '224', 'ffd7ff': '225', 
    'ffff00': '226', 'ffff5f': '227', 'ffff87': '228', 'ffffaf': '229', 'ffffd7': '230', 
    'ffffff': '231', '080808': '232', '121212': '233', '1c1c1c': '234', '262626': '235', 
    '303030': '236', '3a3a3a': '237', '444444': '238', '4e4e4e': '239', '585858': '240', 
    '626262': '241', '6c6c6c': '242', '767676': '243', '808080': '244', '8a8a8a': '245', 
    '949494': '246', '9e9e9e': '247', 'a8a8a8': '248', 'b2b2b2': '249', 'bcbcbc': '250', 
    'c6c6c6': '251', 'd0d0d0': '252', 'dadada': '253', 'e4e4e4': '254', 'eeeeee': '255', 
} 

## Example line from a vim colorscheme file 
##hi Normal   ctermfg=NONE ctermbg=NONE gui=NONE guifg=#b7af9f guibg=#202020 

def Decompose(hexval): 
    return float(int(hexval[0:2], 16)), float(int(hexval[2:4], 16)), float(int(hexval[4:6], 16)) 

def Normalize(r, g, b): 
    magsqr = r*r + g*g + b*b 
    if magsqr < 0.0001: 
     return 0.0, 0.0, 0.0 
    n = 1.0/math.sqrt(magsqr) 
    return r*n, g*n, b*n 

def ColorDist(c1, c2): 
    c1r, c1g, c1b = Decompose(c1) 
    c2r, c2g, c2b = Decompose(c2) 

    dr = c1r - c2r 
    dg = c1g - c2g 
    db = c1b - c2b 
    return dr*dr + dg*dg + db*db 

def BestMatch(hexval): 
    best = None 
    bestdist = 0.0 
    for key in colors.keys(): 
     dist = ColorDist(hexval, key) 
     if best is None or dist < bestdist: 
      best = colors[key] 
      bestdist = dist 
    return best 

##     1 2    3 4  5  6 
fg = re.compile(r'^(.*)(ctermfg=)NONE(.*)(guifg=#)([^ ]*)(.*)\n$') 
bg = re.compile(r'^(.*)(ctermbg=)NONE(.*)(guibg=#)([^ ]*)(.*)\n$') 

with open(r'input_color_scheme.vim', 'r') as f: 
    with open(r'output_color_scheme.vim', 'w') as fout: 
     for line in f.readlines(): 
      fgmatch = fg.match(line) 
      if fgmatch is not None: 
       line = (fgmatch.group(1) + 
         fgmatch.group(2) + 
         BestMatch(fgmatch.group(5)) + 
         fgmatch.group(3) + 
         fgmatch.group(4) + 
         fgmatch.group(5) + 
         fgmatch.group(6)) + '\n' 

      bgmatch = bg.match(line) 
      if bgmatch is not None: 
       line = (bgmatch.group(1) + 
         bgmatch.group(2) + 
         BestMatch(bgmatch.group(5)) + 
         bgmatch.group(3) + 
         bgmatch.group(4) + 
         bgmatch.group(5) + 
         bgmatch.group(6) + '\n') 

      ## -- print the line 
      fout.write(line) 
+0

Dzięki za scenariusz. Użyłeś kolorowego stołu, aby znaleźć kolor N. Czy istnieje sposób na znalezienie go bez stołu? Sprawdziłem również "desert256.vim" i dowiedziałem się, że konwertowali RGB -> XYZ, a następnie użyli '16 + (x * 16) + (y * 4) + z' dla terminala 88-kolorowego i' 16 + (x * 36) + (y * 6) + z' dla 256-kolorowego terminalu, aby znaleźć N dla koloruN. Nie rozumiem ich formuły, czy wiesz, jak do tego doszli? (Większość schematów kolorów VIM 256 używa tej samej formuły) – markfw

2

Idź do Wolfram Alpha, wpisać wartość hex czyli „#acdffa”. Przejdź do sekcji "Najbliżej nazwane kolory HTML"

Wiem, że to nie jest kod, ale powiedziałeś "algorytm/droga".

Cheers

3

Jest to implementacja C, chociaż powinny być łatwo przekształcić go w innych językach, ale należy pamiętać, że używa arytmetyki liczb całkowitych:

// Convert RGB24 to xterm-256 8-bit value 
// For simplicity, assume RGB space is perceptually uniform. 
// There are 5 places where one of two outputs needs to be chosen when the 
// input is the exact middle: 
// - The r/g/b channels and the gray value: the higher value output is chosen. 
// - If the gray and color have same distance from the input - color is chosen. 
static int rgb_to_x256(uint8_t r, uint8_t g, uint8_t b) 
{ 
    // Calculate the nearest 0-based color index at 16 .. 231 
# define v2ci(v) (v < 48 ? 0 : v < 115 ? 1 : (v - 35)/40) 
    int ir = v2ci(r), ig = v2ci(g), ib = v2ci(b); // 0..5 each 
# define color_index() (36 * ir + 6 * ig + ib) /* 0..215, lazy evaluation */ 

    // Calculate the nearest 0-based gray index at 232 .. 255 
    int average = (r + g + b)/3; 
    int gray_index = average > 238 ? 23 : (average - 3)/10; // 0..23 

    // Calculate the represented colors back from the index 
    static const int i2cv[6] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff}; 
    int cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib]; // r/g/b, 0..255 each 
    int gv = 8 + 10 * gray_index; // same value for r/g/b, 0..255 

    // Return the one which is nearer to the original input rgb value 
# define dist_square(A,B,C, a,b,c) ((A-a)*(A-a) + (B-b)*(B-b) + (C-c)*(C-c)) 
    int color_err = dist_square(cr, cg, cb, r, g, b); 
    int gray_err = dist_square(gv, gv, gv, r, g, b); 
    return color_err <= gray_err ? 16 + color_index() : 232 + gray_index; 
} 

Jest to ta sama realizacja, która jest obecnie używany przez tmux i mpv. Możesz znaleźć wyjaśnienie algorytmu na tmux pull request on github.