File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / colour.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    1: /* $OpenBSD$ */
    2: 
    3: /*
    4:  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
    5:  * Copyright (c) 2016 Avi Halachmi <avihpit@yahoo.com>
    6:  *
    7:  * Permission to use, copy, modify, and distribute this software for any
    8:  * purpose with or without fee is hereby granted, provided that the above
    9:  * copyright notice and this permission notice appear in all copies.
   10:  *
   11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   16:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   17:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18:  */
   19: 
   20: #include <sys/types.h>
   21: 
   22: #include <ctype.h>
   23: #include <stdlib.h>
   24: #include <string.h>
   25: 
   26: #include "tmux.h"
   27: 
   28: static int
   29: colour_dist_sq(int R, int G, int B, int r, int g, int b)
   30: {
   31: 	return ((R - r) * (R - r) + (G - g) * (G - g) + (B - b) * (B - b));
   32: }
   33: 
   34: static int
   35: colour_to_6cube(int v)
   36: {
   37: 	if (v < 48)
   38: 		return (0);
   39: 	if (v < 114)
   40: 		return (1);
   41: 	return ((v - 35) / 40);
   42: }
   43: 
   44: /*
   45:  * Convert an RGB triplet to the xterm(1) 256 colour palette.
   46:  *
   47:  * xterm provides a 6x6x6 colour cube (16 - 231) and 24 greys (232 - 255). We
   48:  * map our RGB colour to the closest in the cube, also work out the closest
   49:  * grey, and use the nearest of the two.
   50:  *
   51:  * Note that the xterm has much lower resolution for darker colours (they are
   52:  * not evenly spread out), so our 6 levels are not evenly spread: 0x0, 0x5f
   53:  * (95), 0x87 (135), 0xaf (175), 0xd7 (215) and 0xff (255). Greys are more
   54:  * evenly spread (8, 18, 28 ... 238).
   55:  */
   56: int
   57: colour_find_rgb(u_char r, u_char g, u_char b)
   58: {
   59: 	static const int	q2c[6] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff };
   60: 	int			qr, qg, qb, cr, cg, cb, d, idx;
   61: 	int			grey_avg, grey_idx, grey;
   62: 
   63: 	/* Map RGB to 6x6x6 cube. */
   64: 	qr = colour_to_6cube(r); cr = q2c[qr];
   65: 	qg = colour_to_6cube(g); cg = q2c[qg];
   66: 	qb = colour_to_6cube(b); cb = q2c[qb];
   67: 
   68: 	/* If we have hit the colour exactly, return early. */
   69: 	if (cr == r && cg == g && cb == b)
   70: 		return ((16 + (36 * qr) + (6 * qg) + qb) | COLOUR_FLAG_256);
   71: 
   72: 	/* Work out the closest grey (average of RGB). */
   73: 	grey_avg = (r + g + b) / 3;
   74: 	if (grey_avg > 238)
   75: 		grey_idx = 23;
   76: 	else
   77: 		grey_idx = (grey_avg - 3) / 10;
   78: 	grey = 8 + (10 * grey_idx);
   79: 
   80: 	/* Is grey or 6x6x6 colour closest? */
   81: 	d = colour_dist_sq(cr, cg, cb, r, g, b);
   82: 	if (colour_dist_sq(grey, grey, grey, r, g, b) < d)
   83: 		idx = 232 + grey_idx;
   84: 	else
   85: 		idx = 16 + (36 * qr) + (6 * qg) + qb;
   86: 	return (idx | COLOUR_FLAG_256);
   87: }
   88: 
   89: /* Join RGB into a colour. */
   90: int
   91: colour_join_rgb(u_char r, u_char g, u_char b)
   92: {
   93: 	return ((((int)((r) & 0xff)) << 16) |
   94: 	    (((int)((g) & 0xff)) << 8) |
   95: 	    (((int)((b) & 0xff))) | COLOUR_FLAG_RGB);
   96: }
   97: 
   98: /* Split colour into RGB. */
   99: void
  100: colour_split_rgb(int c, u_char *r, u_char *g, u_char *b)
  101: {
  102: 	*r = (c >> 16) & 0xff;
  103: 	*g = (c >> 8) & 0xff;
  104: 	*b = c & 0xff;
  105: }
  106: 
  107: /* Convert colour to a string. */
  108: const char *
  109: colour_tostring(int c)
  110: {
  111: 	static char	s[32];
  112: 	u_char		r, g, b;
  113: 
  114: 	if (c & COLOUR_FLAG_RGB) {
  115: 		colour_split_rgb(c, &r, &g, &b);
  116: 		xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
  117: 		return (s);
  118: 	}
  119: 
  120: 	if (c & COLOUR_FLAG_256) {
  121: 		xsnprintf(s, sizeof s, "colour%u", c & 0xff);
  122: 		return (s);
  123: 	}
  124: 
  125: 	switch (c) {
  126: 	case 0:
  127: 		return ("black");
  128: 	case 1:
  129: 		return ("red");
  130: 	case 2:
  131: 		return ("green");
  132: 	case 3:
  133: 		return ("yellow");
  134: 	case 4:
  135: 		return ("blue");
  136: 	case 5:
  137: 		return ("magenta");
  138: 	case 6:
  139: 		return ("cyan");
  140: 	case 7:
  141: 		return ("white");
  142: 	case 8:
  143: 		return ("default");
  144: 	case 90:
  145: 		return ("brightblack");
  146: 	case 91:
  147: 		return ("brightred");
  148: 	case 92:
  149: 		return ("brightgreen");
  150: 	case 93:
  151: 		return ("brightyellow");
  152: 	case 94:
  153: 		return ("brightblue");
  154: 	case 95:
  155: 		return ("brightmagenta");
  156: 	case 96:
  157: 		return ("brightcyan");
  158: 	case 97:
  159: 		return ("brightwhite");
  160: 	}
  161: 	return (NULL);
  162: }
  163: 
  164: /* Convert colour from string. */
  165: int
  166: colour_fromstring(const char *s)
  167: {
  168: 	const char	*errstr;
  169: 	const char	*cp;
  170: 	int		 n;
  171: 	u_char		 r, g, b;
  172: 
  173: 	if (*s == '#' && strlen(s) == 7) {
  174: 		for (cp = s + 1; isxdigit((u_char) *cp); cp++)
  175: 			;
  176: 		if (*cp != '\0')
  177: 			return (-1);
  178: 		n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &r, &g, &b);
  179: 		if (n != 3)
  180: 			return (-1);
  181: 		return (colour_join_rgb(r, g, b));
  182: 	}
  183: 
  184: 	if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
  185: 		n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr);
  186: 		if (errstr != NULL)
  187: 			return (-1);
  188: 		return (n | COLOUR_FLAG_256);
  189: 	}
  190: 
  191: 	if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
  192: 		return (0);
  193: 	if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
  194: 		return (1);
  195: 	if (strcasecmp(s, "green") == 0 || strcmp(s, "2") == 0)
  196: 		return (2);
  197: 	if (strcasecmp(s, "yellow") == 0 || strcmp(s, "3") == 0)
  198: 		return (3);
  199: 	if (strcasecmp(s, "blue") == 0 || strcmp(s, "4") == 0)
  200: 		return (4);
  201: 	if (strcasecmp(s, "magenta") == 0 || strcmp(s, "5") == 0)
  202: 		return (5);
  203: 	if (strcasecmp(s, "cyan") == 0 || strcmp(s, "6") == 0)
  204: 		return (6);
  205: 	if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0)
  206: 		return (7);
  207: 	if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0)
  208: 		return (8);
  209: 	if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0)
  210: 		return (90);
  211: 	if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0)
  212: 		return (91);
  213: 	if (strcasecmp(s, "brightgreen") == 0 || strcmp(s, "92") == 0)
  214: 		return (92);
  215: 	if (strcasecmp(s, "brightyellow") == 0 || strcmp(s, "93") == 0)
  216: 		return (93);
  217: 	if (strcasecmp(s, "brightblue") == 0 || strcmp(s, "94") == 0)
  218: 		return (94);
  219: 	if (strcasecmp(s, "brightmagenta") == 0 || strcmp(s, "95") == 0)
  220: 		return (95);
  221: 	if (strcasecmp(s, "brightcyan") == 0 || strcmp(s, "96") == 0)
  222: 		return (96);
  223: 	if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0)
  224: 		return (97);
  225: 	return (-1);
  226: }
  227: 
  228: /* Convert 256 colour palette to 16. */
  229: u_char
  230: colour_256to16(u_char c)
  231: {
  232: 	static const u_char table[256] = {
  233: 		 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
  234: 		 0,  4,  4,  4, 12, 12,  2,  6,  4,  4, 12, 12,  2,  2,  6,  4,
  235: 		12, 12,  2,  2,  2,  6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
  236: 		10, 10, 10, 14,  1,  5,  4,  4, 12, 12,  3,  8,  4,  4, 12, 12,
  237: 		 2,  2,  6,  4, 12, 12,  2,  2,  2,  6, 12, 12, 10, 10, 10, 10,
  238: 		14, 12, 10, 10, 10, 10, 10, 14,  1,  1,  5,  4, 12, 12,  1,  1,
  239: 		 5,  4, 12, 12,  3,  3,  8,  4, 12, 12,  2,  2,  2,  6, 12, 12,
  240: 		10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,  1,  1,  1,  5,
  241: 		12, 12,  1,  1,  1,  5, 12, 12,  1,  1,  1,  5, 12, 12,  3,  3,
  242: 		 3,  7, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,
  243: 		 9,  9,  9,  9, 13, 12,  9,  9,  9,  9, 13, 12,  9,  9,  9,  9,
  244: 		13, 12,  9,  9,  9,  9, 13, 12, 11, 11, 11, 11,  7, 12, 10, 10,
  245: 		10, 10, 10, 14,  9,  9,  9,  9,  9, 13,  9,  9,  9,  9,  9, 13,
  246: 		 9,  9,  9,  9,  9, 13,  9,  9,  9,  9,  9, 13,  9,  9,  9,  9,
  247: 		 9, 13, 11, 11, 11, 11, 11, 15,  0,  0,  0,  0,  0,  0,  8,  8,
  248: 		 8,  8,  8,  8,  7,  7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15
  249: 	};
  250: 
  251: 	return (table[c]);
  252: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>