123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- /**
- * colors.js - color-related functions for blessed.
- * Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
- * https://github.com/chjj/blessed
- */
- exports.match = function(r1, g1, b1) {
- if (typeof r1 === 'string') {
- var hex = r1;
- if (hex[0] !== '#') {
- return -1;
- }
- hex = exports.hexToRGB(hex);
- r1 = hex[0], g1 = hex[1], b1 = hex[2];
- } else if (Array.isArray(r1)) {
- b1 = r1[2], g1 = r1[1], r1 = r1[0];
- }
- var hash = (r1 << 16) | (g1 << 8) | b1;
- if (exports._cache[hash] != null) {
- return exports._cache[hash];
- }
- var ldiff = Infinity
- , li = -1
- , i = 0
- , c
- , r2
- , g2
- , b2
- , diff;
- for (; i < exports.vcolors.length; i++) {
- c = exports.vcolors[i];
- r2 = c[0];
- g2 = c[1];
- b2 = c[2];
- diff = colorDistance(r1, g1, b1, r2, g2, b2);
- if (diff === 0) {
- li = i;
- break;
- }
- if (diff < ldiff) {
- ldiff = diff;
- li = i;
- }
- }
- return exports._cache[hash] = li;
- };
- exports.RGBToHex = function(r, g, b) {
- if (Array.isArray(r)) {
- b = r[2], g = r[1], r = r[0];
- }
- function hex(n) {
- n = n.toString(16);
- if (n.length < 2) n = '0' + n;
- return n;
- }
- return '#' + hex(r) + hex(g) + hex(b);
- };
- exports.hexToRGB = function(hex) {
- if (hex.length === 4) {
- hex = hex[0]
- + hex[1] + hex[1]
- + hex[2] + hex[2]
- + hex[3] + hex[3];
- }
- var col = parseInt(hex.substring(1), 16)
- , r = (col >> 16) & 0xff
- , g = (col >> 8) & 0xff
- , b = col & 0xff;
- return [r, g, b];
- };
- // As it happens, comparing how similar two colors are is really hard. Here is
- // one of the simplest solutions, which doesn't require conversion to another
- // color space, posted on stackoverflow[1]. Maybe someone better at math can
- // propose a superior solution.
- // [1] http://stackoverflow.com/questions/1633828
- function colorDistance(r1, g1, b1, r2, g2, b2) {
- return Math.pow(30 * (r1 - r2), 2)
- + Math.pow(59 * (g1 - g2), 2)
- + Math.pow(11 * (b1 - b2), 2);
- }
- // This might work well enough for a terminal's colors: treat RGB as XYZ in a
- // 3-dimensional space and go midway between the two points.
- exports.mixColors = function(c1, c2, alpha) {
- // if (c1 === 0x1ff) return c1;
- // if (c2 === 0x1ff) return c1;
- if (c1 === 0x1ff) c1 = 0;
- if (c2 === 0x1ff) c2 = 0;
- if (alpha == null) alpha = 0.5;
- c1 = exports.vcolors[c1];
- var r1 = c1[0];
- var g1 = c1[1];
- var b1 = c1[2];
- c2 = exports.vcolors[c2];
- var r2 = c2[0];
- var g2 = c2[1];
- var b2 = c2[2];
- r1 += (r2 - r1) * alpha | 0;
- g1 += (g2 - g1) * alpha | 0;
- b1 += (b2 - b1) * alpha | 0;
- return exports.match([r1, g1, b1]);
- };
- exports.blend = function blend(attr, attr2, alpha) {
- var name, i, c, nc;
- var bg = attr & 0x1ff;
- if (attr2 != null) {
- var bg2 = attr2 & 0x1ff;
- if (bg === 0x1ff) bg = 0;
- if (bg2 === 0x1ff) bg2 = 0;
- bg = exports.mixColors(bg, bg2, alpha);
- } else {
- if (blend._cache[bg] != null) {
- bg = blend._cache[bg];
- // } else if (bg < 8) {
- // bg += 8;
- } else if (bg >= 8 && bg <= 15) {
- bg -= 8;
- } else {
- name = exports.ncolors[bg];
- if (name) {
- for (i = 0; i < exports.ncolors.length; i++) {
- if (name === exports.ncolors[i] && i !== bg) {
- c = exports.vcolors[bg];
- nc = exports.vcolors[i];
- if (nc[0] + nc[1] + nc[2] < c[0] + c[1] + c[2]) {
- blend._cache[bg] = i;
- bg = i;
- break;
- }
- }
- }
- }
- }
- }
- attr &= ~0x1ff;
- attr |= bg;
- var fg = (attr >> 9) & 0x1ff;
- if (attr2 != null) {
- var fg2 = (attr2 >> 9) & 0x1ff;
- // 0, 7, 188, 231, 251
- if (fg === 0x1ff) {
- // XXX workaround
- fg = 248;
- } else {
- if (fg === 0x1ff) fg = 7;
- if (fg2 === 0x1ff) fg2 = 7;
- fg = exports.mixColors(fg, fg2, alpha);
- }
- } else {
- if (blend._cache[fg] != null) {
- fg = blend._cache[fg];
- // } else if (fg < 8) {
- // fg += 8;
- } else if (fg >= 8 && fg <= 15) {
- fg -= 8;
- } else {
- name = exports.ncolors[fg];
- if (name) {
- for (i = 0; i < exports.ncolors.length; i++) {
- if (name === exports.ncolors[i] && i !== fg) {
- c = exports.vcolors[fg];
- nc = exports.vcolors[i];
- if (nc[0] + nc[1] + nc[2] < c[0] + c[1] + c[2]) {
- blend._cache[fg] = i;
- fg = i;
- break;
- }
- }
- }
- }
- }
- }
- attr &= ~(0x1ff << 9);
- attr |= fg << 9;
- return attr;
- };
- exports.blend._cache = {};
- exports._cache = {};
- exports.reduce = function(color, total) {
- if (color >= 16 && total <= 16) {
- color = exports.ccolors[color];
- } else if (color >= 8 && total <= 8) {
- color -= 8;
- } else if (color >= 2 && total <= 2) {
- color %= 2;
- }
- return color;
- };
- // XTerm Colors
- // These were actually tough to track down. The xterm source only uses color
- // keywords. The X11 source needed to be examined to find the actual values.
- // They then had to be mapped to rgb values and then converted to hex values.
- exports.xterm = [
- '#000000', // black
- '#cd0000', // red3
- '#00cd00', // green3
- '#cdcd00', // yellow3
- '#0000ee', // blue2
- '#cd00cd', // magenta3
- '#00cdcd', // cyan3
- '#e5e5e5', // gray90
- '#7f7f7f', // gray50
- '#ff0000', // red
- '#00ff00', // green
- '#ffff00', // yellow
- '#5c5cff', // rgb:5c/5c/ff
- '#ff00ff', // magenta
- '#00ffff', // cyan
- '#ffffff' // white
- ];
- // Seed all 256 colors. Assume xterm defaults.
- // Ported from the xterm color generation script.
- exports.colors = (function() {
- var cols = exports.colors = []
- , _cols = exports.vcolors = []
- , r
- , g
- , b
- , i
- , l;
- function hex(n) {
- n = n.toString(16);
- if (n.length < 2) n = '0' + n;
- return n;
- }
- function push(i, r, g, b) {
- cols[i] = '#' + hex(r) + hex(g) + hex(b);
- _cols[i] = [r, g, b];
- }
- // 0 - 15
- exports.xterm.forEach(function(c, i) {
- c = parseInt(c.substring(1), 16);
- push(i, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
- });
- // 16 - 231
- for (r = 0; r < 6; r++) {
- for (g = 0; g < 6; g++) {
- for (b = 0; b < 6; b++) {
- i = 16 + (r * 36) + (g * 6) + b;
- push(i,
- r ? (r * 40 + 55) : 0,
- g ? (g * 40 + 55) : 0,
- b ? (b * 40 + 55) : 0);
- }
- }
- }
- // 232 - 255 are grey.
- for (g = 0; g < 24; g++) {
- l = (g * 10) + 8;
- i = 232 + g;
- push(i, l, l, l);
- }
- return cols;
- })();
- // Map higher colors to the first 8 colors.
- // This allows translation of high colors to low colors on 8-color terminals.
- exports.ccolors = (function() {
- var _cols = exports.vcolors.slice()
- , cols = exports.colors.slice()
- , out;
- exports.vcolors = exports.vcolors.slice(0, 8);
- exports.colors = exports.colors.slice(0, 8);
- out = cols.map(exports.match);
- exports.colors = cols;
- exports.vcolors = _cols;
- exports.ccolors = out;
- return out;
- })();
- var colorNames = exports.colorNames = {
- // special
- default: -1,
- normal: -1,
- bg: -1,
- fg: -1,
- // normal
- black: 0,
- red: 1,
- green: 2,
- yellow: 3,
- blue: 4,
- magenta: 5,
- cyan: 6,
- white: 7,
- // light
- lightblack: 8,
- lightred: 9,
- lightgreen: 10,
- lightyellow: 11,
- lightblue: 12,
- lightmagenta: 13,
- lightcyan: 14,
- lightwhite: 15,
- // bright
- brightblack: 8,
- brightred: 9,
- brightgreen: 10,
- brightyellow: 11,
- brightblue: 12,
- brightmagenta: 13,
- brightcyan: 14,
- brightwhite: 15,
- // alternate spellings
- grey: 8,
- gray: 8,
- lightgrey: 7,
- lightgray: 7,
- brightgrey: 7,
- brightgray: 7
- };
- exports.convert = function(color) {
- if (typeof color === 'number') {
- ;
- } else if (typeof color === 'string') {
- color = color.replace(/[\- ]/g, '');
- if (colorNames[color] != null) {
- color = colorNames[color];
- } else {
- color = exports.match(color);
- }
- } else if (Array.isArray(color)) {
- color = exports.match(color);
- } else {
- color = -1;
- }
- return color !== -1 ? color : 0x1ff;
- };
- // Map higher colors to the first 8 colors.
- // This allows translation of high colors to low colors on 8-color terminals.
- // Why the hell did I do this by hand?
- exports.ccolors = {
- blue: [
- 4,
- 12,
- [17, 21],
- [24, 27],
- [31, 33],
- [38, 39],
- 45,
- [54, 57],
- [60, 63],
- [67, 69],
- [74, 75],
- 81,
- [91, 93],
- [97, 99],
- [103, 105],
- [110, 111],
- 117,
- [128, 129],
- [134, 135],
- [140, 141],
- [146, 147],
- 153,
- 165,
- 171,
- 177,
- 183,
- 189
- ],
- green: [
- 2,
- 10,
- 22,
- [28, 29],
- [34, 36],
- [40, 43],
- [46, 50],
- [64, 65],
- [70, 72],
- [76, 79],
- [82, 86],
- [106, 108],
- [112, 115],
- [118, 122],
- [148, 151],
- [154, 158],
- [190, 194]
- ],
- cyan: [
- 6,
- 14,
- 23,
- 30,
- 37,
- 44,
- 51,
- 66,
- 73,
- 80,
- 87,
- 109,
- 116,
- 123,
- 152,
- 159,
- 195
- ],
- red: [
- 1,
- 9,
- 52,
- [88, 89],
- [94, 95],
- [124, 126],
- [130, 132],
- [136, 138],
- [160, 163],
- [166, 169],
- [172, 175],
- [178, 181],
- [196, 200],
- [202, 206],
- [208, 212],
- [214, 218],
- [220, 224]
- ],
- magenta: [
- 5,
- 13,
- 53,
- 90,
- 96,
- 127,
- 133,
- 139,
- 164,
- 170,
- 176,
- 182,
- 201,
- 207,
- 213,
- 219,
- 225
- ],
- yellow: [
- 3,
- 11,
- 58,
- [100, 101],
- [142, 144],
- [184, 187],
- [226, 230]
- ],
- black: [
- 0,
- 8,
- 16,
- 59,
- 102,
- [232, 243]
- ],
- white: [
- 7,
- 15,
- 145,
- 188,
- 231,
- [244, 255]
- ]
- };
- exports.ncolors = [];
- Object.keys(exports.ccolors).forEach(function(name) {
- exports.ccolors[name].forEach(function(offset) {
- if (typeof offset === 'number') {
- exports.ncolors[offset] = name;
- exports.ccolors[offset] = exports.colorNames[name];
- return;
- }
- for (var i = offset[0], l = offset[1]; i <= l; i++) {
- exports.ncolors[i] = name;
- exports.ccolors[i] = exports.colorNames[name];
- }
- });
- delete exports.ccolors[name];
- });
|