commit 41cefd3da9852be69c40139eda82ed24b7a59d31
parent 27ed7c32a15c28ff85a91f55190972b00d1fbcac
Author: Santtu Lakkala <inz@inz.fi>
Date: Mon, 20 Jul 2020 10:48:59 +0300
Implement 256 and 16 color modes
Diffstat:
M | nyancat.c | | | 119 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
1 file changed, 107 insertions(+), 12 deletions(-)
diff --git a/nyancat.c b/nyancat.c
@@ -48,6 +48,7 @@ struct lolcat {
bool was_bold;
bool was_reverse;
bool was_underline;
+ enum { TRUECOLOR, INDEXED256, INDEXED16 } mode;
void (*write)(const char *buffer, size_t buflen, void *data);
void *write_data;
@@ -137,6 +138,7 @@ struct lolcat *lolcat_init(void (*write_cb)(const char *buffer, size_t buflen,
rv->write_data = cbdata;
rv->fg = 0xc0c0c0;
rv->bg = 0x000000;
+ rv->mode = TRUECOLOR;
return rv;
}
@@ -222,6 +224,52 @@ static int _add(int a, int b, double amount)
CLAMP(bl, 0, 255);
}
+static inline uint8_t absd(uint8_t a, uint8_t b)
+{
+ if (a > b)
+ return a - b;
+ return b - a;
+}
+
+static inline int _index16(uint32_t col, bool *bright)
+{
+ uint8_t r = col >> 16;
+ uint8_t g = (col >> 8) & 255;
+ uint8_t b = col & 255;
+
+ uint8_t ri = ((uint16_t)r + 64) * 2 / 256;
+ uint8_t gi = ((uint16_t)g + 64) * 2 / 256;
+ uint8_t bi = ((uint16_t)b + 64) * 2 / 256;
+
+ if (ri == 2 || gi == 2 || bi == 2) {
+ ri = r > 127U;
+ gi = g > 127U;
+ bi = b > 127U;
+ *bright = true;
+ } else {
+ *bright = false;
+ }
+
+ return ri | bi << 1 | gi << 2;
+}
+
+static inline int _index256(uint32_t col)
+{
+ uint8_t r = col >> 16;
+ uint8_t g = (col >> 8) & 255;
+ uint8_t b = col & 255;
+ uint8_t cr = r < 28 ? 0 : (r - 28) * 5 / 228 + 1;
+ uint8_t cb = b < 28 ? 0 : (b - 28) * 5 / 228 + 1;
+ uint8_t cg = g < 28 ? 0 : (g - 28) * 5 / 228 + 1;
+
+ uint8_t gs = ((uint16_t)r + g + b) / 3 * 32 / 256;
+
+ if (absd(cr * 40 + !!cr * 55, r) + absd(cg * 40 + !!cg * 55, g) + absd(cb + 40 + !!cb * 55, b) <
+ absd(gs, r) + absd(gs, g) + absd(gs, b))
+ return cr * 36 + cg * 6 + cb + 16;
+ return g + 232;
+}
+
static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len)
{
char buffer[128] = "\x1b[";
@@ -234,6 +282,17 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len)
return;
}
+ if (lc->bold)
+ col = _bold(lc->fg);
+ else
+ col = lc->fg;
+ col = _add(rainbow(0.03, nyan(lc->x, lc->y)), col, 0.5);
+
+ if (lc->mode == INDEXED16)
+ col = _index16(col, &lc->bold);
+ else if (lc->mode == INDEXED256)
+ col = _index256(col);
+
if ((lc->was_bold && !lc->bold) ||
(lc->was_reverse && !lc->reverse)) {
lc->was_underline = false;
@@ -260,16 +319,17 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len)
lc->was_reverse = true;
}
- if (lc->bold)
- col = _bold(lc->fg);
+ if (lc->mode == INDEXED16)
+ bw += sprintf(bw, "3%dm%.*s",
+ col, (int)len, u8_char);
+ else if (lc->mode == INDEXED256)
+ bw += sprintf(bw, "38;5;%dm%.*s",
+ col, (int)len, u8_char);
else
- col = lc->fg;
- col = _add(rainbow(0.03, nyan(lc->x, lc->y)), col, 0.5);
-
- bw += sprintf(bw, "38;2;%d;%d;%dm%.*s",
- col >> 16,
- (col >> 8) & 255,
- col & 255, (int)len, u8_char);
+ bw += sprintf(bw, "38;2;%d;%d;%dm%.*s",
+ col >> 16,
+ (col >> 8) & 255,
+ col & 255, (int)len, u8_char);
lc->write(buffer, bw - buffer, lc->write_data);
}
@@ -489,13 +549,19 @@ void lolcat_set_size(struct lolcat *lc, int w, int h)
lc->h = h;
}
+static void usage()
+{
+ fprintf(stderr, "Usage: nyancat [-t2] [file...]\n");
+ exit(0);
+}
+
int main(int argc, char **argv)
{
struct lolcat *lc = lolcat_init(_write, stdout);
char buffer[2048];
size_t used = 0;
struct termios old_tio = { 0 }, new_tio;
- int i;
+ int i = 1;
struct winsize ws = { 0 };
@@ -503,7 +569,36 @@ int main(int argc, char **argv)
!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws))
lolcat_set_size(lc, ws.ws_col, ws.ws_row);
- if (argc < 2) {
+ while (i < argc) {
+ const char *opt;
+ if (argv[i][0] != '-' || argv[i][1] == '\0')
+ break;
+ if (argv[i][1] == '-' && argv[i][2] == '\0') {
+ i++;
+ break;
+ }
+ opt = &argv[i++][1];
+
+ while (*opt) {
+ switch (*opt++) {
+ case 't':
+ lc->mode = TRUECOLOR;
+ break;
+ case '1':
+ lc->mode = INDEXED16;
+ break;
+ case '2':
+ lc->mode = INDEXED256;
+ break;
+ case 'h':
+ default:
+ usage();
+ break;
+ }
+ }
+ }
+
+ if (i >= argc) {
tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio;
@@ -533,7 +628,7 @@ int main(int argc, char **argv)
fflush(stdout);
tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
} else {
- for (i = 1; i < argc; i++) {
+ for (; i < argc; i++) {
int fd;
if (!strcmp(argv[i], "-"))
fd = STDIN_FILENO;