2012-08-01 16 views
6

Estoy buscando un Algoritmo/Forma de convertir un HEX dado (ej. # 111111 R: 0x11, G: 0x11, B: 0x11) al número de color X11 más cercano (El terminal es 88 o 256 colores) usando Python, PHP o script VIM y me preguntaba si alguien aquí sabe una forma o me indica una dirección para hacer esto.Convierte HEX al número de color X11 más cercano

Gracias de antemano.

+0

¿cuál es el * más cercano *? responde eso y tendrás un algoritmo. ¿Es la distancia en el espacio tridimensional? o prefiere preservar a proporciones (color), o amplitud (brillo), etc.? una vez que tiene una métrica para la distancia, simplemente está eligiendo el mínimo. –

+0

@KarolyHorvath - No estoy seguro de qué algoritmo puede darme un mejor resultado, pero explicaré lo que estoy tratando de hacer. Estoy creando un esquema de colores para mi editor VIM. Utilizando la versión GUI de VIM puedo usar colores HEX. Ahora quiero convertir ese número HEX a X11 y configurarlo para la versión de consola de VIM. – markfw

Respuesta

7

que tenía el mismo problema (teniendo un colorscheme vim existente con colores hexagonales gvim y rellenando los valores de color del terminal). Aquí está la escritura que utilicé (aunque la función ColorDist probablemente beneficiarse de una mejor métrica distancia de color como algunos de los otros carteles están sugiriendo)

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

Gracias por el guión. Usaste la tabla de colores para descubrir el colorN. ¿Hay alguna manera de encontrarlo sin tener mesa? También revisé 'desert256.vim' y descubrí que convertían RGB -> XYZ y luego usaban' 16 + (x * 16) + (y * 4) + z' para la terminal de 88 colores y '16 + (x * 36) + (y * 6) + z' para terminal de 256 colores para encontrar N para colorN. No entiendo su fórmula, ¿saben cómo se les ocurrió? (La mayoría de los 256 esquemas de colores VIM usan la misma fórmula) – markfw

2

Ir a Wolfram Alpha, teclee el valor hexadecimal es decir, "#acdffa". Vaya a la sección llamada "Colores HTML nombrados más cercanos"

Sé que esto no es código, pero usted dijo "algorithm/way".

Saludos

3

Ésta es una implementación en C, aunque debe ser fácil de convertirlo a otros idiomas, pero tenga en cuenta que se utiliza aritmética de enteros:

// 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; 
} 

Ésta es la misma aplicación la cual actualmente es utilizado por tmux y mpv. Puede encontrar alguna explicación del algoritmo en el tmux pull request on github.

Cuestiones relacionadas